diff --git a/Libraries/SPTarkov.Server.Core/Generators/BotGenerator.cs b/Libraries/SPTarkov.Server.Core/Generators/BotGenerator.cs
index 5b77eba6..38d0238b 100644
--- a/Libraries/SPTarkov.Server.Core/Generators/BotGenerator.cs
+++ b/Libraries/SPTarkov.Server.Core/Generators/BotGenerator.cs
@@ -171,8 +171,12 @@ public class BotGenerator(
/// BotBase object
protected BotBase GenerateBot(MongoId sessionId, BotBase bot, BotType botJsonTemplate, BotGenerationDetails botGenerationDetails)
{
- var botRoleLowercase = botGenerationDetails.Role.ToLowerInvariant();
- var botLevel = botLevelGenerator.GenerateBotLevel(botJsonTemplate.BotExperience.Level, botGenerationDetails, bot);
+ botGenerationDetails.RoleLowercase = botGenerationDetails.Role.ToLowerInvariant();
+
+ var botLevelDetails = botLevelGenerator.GenerateBotLevel(botJsonTemplate.BotExperience.Level, botGenerationDetails, bot);
+
+ // Assign value for later use
+ botGenerationDetails.BotLevel = botLevelDetails.Level.GetValueOrDefault();
// Generate Id/AId for bot
AddIdsToBot(bot, botGenerationDetails);
@@ -180,13 +184,12 @@ public class BotGenerator(
// Only filter bot equipment, never players
if (!botGenerationDetails.IsPlayerScav)
{
- botEquipmentFilterService.FilterBotEquipment(sessionId, botJsonTemplate, botLevel.Level.Value, botGenerationDetails);
+ botEquipmentFilterService.FilterBotEquipment(sessionId, botJsonTemplate, botGenerationDetails);
}
bot.Info.Nickname = botNameService.GenerateUniqueBotNickname(
botJsonTemplate,
botGenerationDetails,
- botRoleLowercase,
BotConfig.BotRolesThatMustHaveUniqueName
);
@@ -194,7 +197,7 @@ public class BotGenerator(
bot.Info.LowerNickname = botGenerationDetails.IsPmc ? bot.Info.Nickname.ToLowerInvariant() : string.Empty;
// Only run when generating a 'fake' playerscav, not actual player scav
- if (!botGenerationDetails.IsPlayerScav && ShouldSimulatePlayerScav(botRoleLowercase))
+ if (!botGenerationDetails.IsPlayerScav && ShouldSimulatePlayerScav(botGenerationDetails.RoleLowercase))
{
botNameService.AddRandomPmcNameToBotMainProfileNicknameProperty(bot);
SetRandomisedGameVersionAndCategory(bot.Info);
@@ -217,8 +220,8 @@ public class BotGenerator(
bot.Hideout = null;
}
- bot.Info.Experience = botLevel.Exp;
- bot.Info.Level = botLevel.Level;
+ bot.Info.Experience = botLevelDetails.Exp;
+ bot.Info.Level = botLevelDetails.Level;
bot.Info.Settings.Experience = GetExperienceRewardForKillByDifficulty(
botJsonTemplate.BotExperience.Reward,
botGenerationDetails.BotDifficulty,
@@ -248,22 +251,16 @@ public class BotGenerator(
{
AddAdditionalPocketLootWeightsForUnheardBot(botJsonTemplate);
}
+
+ botGenerationDetails.GameVersion = bot.Info.GameVersion;
}
// Add drip
SetBotAppearance(bot, botJsonTemplate.BotAppearance, botGenerationDetails);
- bot.Inventory = botInventoryGenerator.GenerateInventory(
- bot.Id.Value,
- sessionId,
- botJsonTemplate,
- botRoleLowercase,
- botGenerationDetails,
- bot.Info.Level.Value,
- bot.Info.GameVersion
- );
+ bot.Inventory = botInventoryGenerator.GenerateInventory(bot.Id.Value, sessionId, botJsonTemplate, botGenerationDetails);
- if (BotConfig.BotRolesWithDogTags.Contains(botRoleLowercase))
+ if (BotConfig.BotRolesWithDogTags.Contains(botGenerationDetails.RoleLowercase))
{
AddDogtagToBot(bot);
}
diff --git a/Libraries/SPTarkov.Server.Core/Generators/BotInventoryGenerator.cs b/Libraries/SPTarkov.Server.Core/Generators/BotInventoryGenerator.cs
index 49727c7a..cb22c20d 100644
--- a/Libraries/SPTarkov.Server.Core/Generators/BotInventoryGenerator.cs
+++ b/Libraries/SPTarkov.Server.Core/Generators/BotInventoryGenerator.cs
@@ -70,45 +70,26 @@ public class BotInventoryGenerator(
/// Bots unique identifier
/// Session id
/// Base json db file for the bot having its loot generated
- /// Role bot has (assault/pmcBot)
/// Details related to generating a bot
- /// Level of bot being generated
- /// Game version for bot, only really applies for PMCs
/// PmcInventory object with equipment/weapons/loot
public BotBaseInventory GenerateInventory(
MongoId botId,
MongoId sessionId,
BotType botJsonTemplate,
- string botRole,
- BotGenerationDetails botGenerationDetails,
- int botLevel,
- string chosenGameVersion
+ BotGenerationDetails botGenerationDetails
)
{
var templateInventory = botJsonTemplate.BotInventory;
var wornItemChances = botJsonTemplate.BotChances;
var itemGenerationLimitsMinMax = botJsonTemplate.BotGeneration;
- var isPmc = botGenerationDetails.IsPmc;
-
// Generate base inventory with no items
var botInventory = GenerateInventoryBase();
// Get generated raid details bot will be spawned in
var raidConfig = profileActivityService.GetProfileActivityRaidData(sessionId)?.RaidConfiguration;
- GenerateAndAddEquipmentToBot(
- botId,
- sessionId,
- templateInventory,
- wornItemChances,
- botRole,
- botInventory,
- botLevel,
- chosenGameVersion,
- isPmc,
- raidConfig
- );
+ GenerateAndAddEquipmentToBot(botId, sessionId, templateInventory, wornItemChances, botInventory, botGenerationDetails, raidConfig);
// Roll weapon spawns (primary/secondary/holster) and generate a weapon for each roll that passed
GenerateAndAddWeaponsToBot(
@@ -117,14 +98,12 @@ public class BotInventoryGenerator(
wornItemChances,
sessionId,
botInventory,
- botRole,
- isPmc,
- itemGenerationLimitsMinMax,
- botLevel
+ botGenerationDetails,
+ itemGenerationLimitsMinMax
);
// Pick loot and add to bots containers (rig/backpack/pockets/secure)
- botLootGenerator.GenerateLoot(botId, sessionId, botJsonTemplate, botGenerationDetails, isPmc, botRole, botInventory, botLevel);
+ botLootGenerator.GenerateLoot(botId, sessionId, botJsonTemplate, botGenerationDetails, botInventory);
// Inventory cache isn't needed, clear to save memory
if (botGenerationDetails.ClearBotContainerCacheAfterGeneration)
@@ -178,32 +157,31 @@ public class BotInventoryGenerator(
/// Session id
/// bot/x.json data from db
/// Chances items will be added to bot
- /// Role bot has (assault/pmcBot)
/// Inventory to add equipment to
- /// Level of bot
- /// Game version for bot, only really applies for PMCs
- /// Is the generated bot a PMC
+ /// Details related to generating a bot
/// RadiConfig
public void GenerateAndAddEquipmentToBot(
MongoId botId,
MongoId sessionId,
BotTypeInventory templateInventory,
Chances wornItemChances,
- string botRole,
BotBaseInventory botInventory,
- int botLevel,
- string chosenGameVersion,
- bool isPmc,
+ BotGenerationDetails botGenerationDetails,
GetRaidConfigurationRequestData? raidConfig
)
{
- if (!BotConfig.Equipment.TryGetValue(botGeneratorHelper.GetBotEquipmentRole(botRole), out var botEquipConfig))
+ if (
+ !BotConfig.Equipment.TryGetValue(
+ botGeneratorHelper.GetBotEquipmentRole(botGenerationDetails.RoleLowercase),
+ out var botEquipConfig
+ )
+ )
{
- logger.Error($"Bot Equipment generation failed, unable to find equipment filters for: {botRole}");
+ logger.Error($"Bot Equipment generation failed, unable to find equipment filters for: {botGenerationDetails.RoleLowercase}");
return;
}
- var randomistionDetails = botHelper.GetBotRandomizationDetails(botLevel, botEquipConfig);
+ var randomistionDetails = botHelper.GetBotRandomizationDetails(botGenerationDetails.BotLevel, botEquipConfig);
// Apply nighttime changes if its nighttime + there's changes to make
if (
@@ -224,13 +202,14 @@ public class BotInventoryGenerator(
}
// Is PMC + generating armband + armband forcing is enabled
- if (PMCConfig.ForceArmband.Enabled && isPmc)
+ if (PMCConfig.ForceArmband.Enabled && botGenerationDetails.IsPmc)
{
// Replace armband pool with single tpl from config
if (templateInventory.Equipment.TryGetValue(EquipmentSlots.ArmBand, out var armbands))
{
// Get tpl based on pmc side
- var armbandTpl = botRole == "pmcusec" ? PMCConfig.ForceArmband.Usec : PMCConfig.ForceArmband.Bear;
+ var armbandTpl =
+ botGenerationDetails.RoleLowercase == "pmcusec" ? PMCConfig.ForceArmband.Usec : PMCConfig.ForceArmband.Bear;
armbands.Clear();
armbands.Add(armbandTpl, 1);
@@ -242,7 +221,7 @@ public class BotInventoryGenerator(
// Get profile of player generating bots, we use their level later on
var pmcProfile = profileHelper.GetPmcProfile(sessionId);
- var botEquipmentRole = botGeneratorHelper.GetBotEquipmentRole(botRole);
+ var botEquipmentRole = botGeneratorHelper.GetBotEquipmentRole(botGenerationDetails.RoleLowercase);
// Iterate over all equipment slots of bot, do it in specific order to reduce conflicts
// e.g. ArmorVest should be generated after TacticalVest
@@ -266,8 +245,8 @@ public class BotInventoryGenerator(
SpawnChances = wornItemChances,
BotData = new BotData
{
- Role = botRole,
- Level = botLevel,
+ Role = botGenerationDetails.RoleLowercase,
+ Level = botGenerationDetails.BotLevel,
EquipmentRole = botEquipmentRole,
},
Inventory = botInventory,
@@ -285,13 +264,17 @@ public class BotInventoryGenerator(
BotId = botId,
RootEquipmentSlot = EquipmentSlots.Pockets,
// Unheard profiles have unique sized pockets
- RootEquipmentPool = GetPocketPoolByGameEdition(chosenGameVersion, templateInventory, isPmc),
+ RootEquipmentPool = GetPocketPoolByGameEdition(
+ botGenerationDetails.GameVersion,
+ templateInventory,
+ botGenerationDetails.IsPmc
+ ),
ModPool = templateInventory.Mods,
SpawnChances = wornItemChances,
BotData = new BotData
{
- Role = botRole,
- Level = botLevel,
+ Role = botGenerationDetails.RoleLowercase,
+ Level = botGenerationDetails.BotLevel,
EquipmentRole = botEquipmentRole,
},
Inventory = botInventory,
@@ -312,8 +295,8 @@ public class BotInventoryGenerator(
SpawnChances = wornItemChances,
BotData = new BotData
{
- Role = botRole,
- Level = botLevel,
+ Role = botGenerationDetails.RoleLowercase,
+ Level = botGenerationDetails.BotLevel,
EquipmentRole = botEquipmentRole,
},
Inventory = botInventory,
@@ -333,8 +316,8 @@ public class BotInventoryGenerator(
SpawnChances = wornItemChances,
BotData = new BotData
{
- Role = botRole,
- Level = botLevel,
+ Role = botGenerationDetails.RoleLowercase,
+ Level = botGenerationDetails.BotLevel,
EquipmentRole = botEquipmentRole,
},
Inventory = botInventory,
@@ -354,8 +337,8 @@ public class BotInventoryGenerator(
SpawnChances = wornItemChances,
BotData = new BotData
{
- Role = botRole,
- Level = botLevel,
+ Role = botGenerationDetails.RoleLowercase,
+ Level = botGenerationDetails.BotLevel,
EquipmentRole = botEquipmentRole,
},
Inventory = botInventory,
@@ -375,8 +358,8 @@ public class BotInventoryGenerator(
SpawnChances = wornItemChances,
BotData = new BotData
{
- Role = botRole,
- Level = botLevel,
+ Role = botGenerationDetails.RoleLowercase,
+ Level = botGenerationDetails.BotLevel,
EquipmentRole = botEquipmentRole,
},
Inventory = botInventory,
@@ -390,14 +373,14 @@ public class BotInventoryGenerator(
if (botEquipConfig.ForceOnlyArmoredRigWhenNoArmor.GetValueOrDefault(false) && !hasArmorVest)
// Filter rigs down to only those with armor
{
- FilterRigsToThoseWithProtection(templateInventory.Equipment, botRole);
+ FilterRigsToThoseWithProtection(templateInventory.Equipment, botGenerationDetails.RoleLowercase);
}
// Optimisation - Remove armored rigs from pool
if (hasArmorVest)
// Filter rigs down to only those with armor
{
- FilterRigsToThoseWithoutProtection(templateInventory.Equipment, botRole);
+ FilterRigsToThoseWithoutProtection(templateInventory.Equipment, botGenerationDetails.RoleLowercase);
}
// Bot is flagged as always needing a vest
@@ -416,8 +399,8 @@ public class BotInventoryGenerator(
SpawnChances = wornItemChances,
BotData = new BotData
{
- Role = botRole,
- Level = botLevel,
+ Role = botGenerationDetails.RoleLowercase,
+ Level = botGenerationDetails.BotLevel,
EquipmentRole = botEquipmentRole,
},
Inventory = botInventory,
@@ -688,20 +671,16 @@ public class BotInventoryGenerator(
/// Chances bot can have equipment equipped
/// Session id
/// Inventory to add weapons to
- /// assault/pmcBot/bossTagilla etc
- /// Is the bot being generated as a pmc
+ /// Details related to generating a bot
/// Limits for items the bot can have
- /// level of bot having weapon generated
public void GenerateAndAddWeaponsToBot(
MongoId botId,
BotTypeInventory templateInventory,
Chances equipmentChances,
MongoId sessionId,
BotBaseInventory botInventory,
- string botRole,
- bool isPmc,
- Generation itemGenerationLimitsMinMax,
- int botLevel
+ BotGenerationDetails botGenerationDetails,
+ Generation itemGenerationLimitsMinMax
)
{
var weaponSlotsToFill = GetDesiredWeaponsForBot(equipmentChances);
@@ -717,10 +696,8 @@ public class BotInventoryGenerator(
templateInventory,
botInventory,
equipmentChances,
- botRole,
- isPmc,
- itemGenerationLimitsMinMax,
- botLevel
+ botGenerationDetails,
+ itemGenerationLimitsMinMax
);
}
}
@@ -759,10 +736,8 @@ public class BotInventoryGenerator(
/// bot/x.json data from db
/// Inventory to add weapon+mags/ammo to
/// Chances bot can have equipment equipped
- /// assault/pmcBot/bossTagilla etc
- /// Is the bot being generated as a pmc
+ /// Details related to generating a bot
///
- ///
public void AddWeaponAndMagazinesToInventory(
MongoId botId,
MongoId sessionId,
@@ -770,21 +745,17 @@ public class BotInventoryGenerator(
BotTypeInventory templateInventory,
BotBaseInventory botInventory,
Chances equipmentChances,
- string botRole,
- bool isPmc,
- Generation itemGenerationWeights,
- int botLevel
+ BotGenerationDetails botGenerationDetails,
+ Generation itemGenerationWeights
)
{
var generatedWeapon = botWeaponGenerator.GenerateRandomWeapon(
sessionId,
weaponSlot.Slot.ToString(),
templateInventory,
+ botGenerationDetails,
botInventory.Equipment.Value,
- equipmentChances.WeaponModsChances,
- botRole,
- isPmc,
- botLevel
+ equipmentChances.WeaponModsChances
);
botInventory.Items.AddRange(generatedWeapon.Weapon);
@@ -794,7 +765,7 @@ public class BotInventoryGenerator(
generatedWeapon,
itemGenerationWeights.Items.Magazines,
botInventory,
- botRole
+ botGenerationDetails.RoleLowercase
);
}
}
diff --git a/Libraries/SPTarkov.Server.Core/Generators/BotLootGenerator.cs b/Libraries/SPTarkov.Server.Core/Generators/BotLootGenerator.cs
index 52290ee0..2601fcff 100644
--- a/Libraries/SPTarkov.Server.Core/Generators/BotLootGenerator.cs
+++ b/Libraries/SPTarkov.Server.Core/Generators/BotLootGenerator.cs
@@ -61,19 +61,13 @@ public class BotLootGenerator(
/// Session id
/// Clone of Base JSON db file for the bot having its loot generated
/// Details relating to generating a bot
- /// Will bot be a pmc
- /// Role of bot, e.g. assault
/// Inventory to add loot to
- /// Level of bot
public void GenerateLoot(
MongoId botId,
MongoId sessionId,
BotType botJsonTemplate,
BotGenerationDetails botGenerationDetails,
- bool isPmc,
- string botRole,
- BotBaseInventory botInventory,
- int botLevel
+ BotBaseInventory botInventory
)
{
// Limits on item types to be added as loot
@@ -93,7 +87,7 @@ public class BotLootGenerator(
|| itemCounts.Grenades.Weights is null
)
{
- logger.Warning(serverLocalisationService.GetText("bot-unable_to_generate_bot_loot", botRole));
+ logger.Warning(serverLocalisationService.GetText("bot-unable_to_generate_bot_loot", botGenerationDetails.RoleLowercase));
return;
}
@@ -110,7 +104,7 @@ public class BotLootGenerator(
var grenadeCount = weightedRandomHelper.GetWeightedValue(itemCounts.Grenades.Weights);
// If bot has been flagged as not having loot, set below counts to 0
- if (BotConfig.DisableLootOnBotTypes.Contains(botRole.ToLowerInvariant()))
+ if (BotConfig.DisableLootOnBotTypes.Contains(botGenerationDetails.RoleLowercase))
{
backpackLootCount = 0;
pocketLootCount = 0;
@@ -119,156 +113,202 @@ public class BotLootGenerator(
}
// Forced pmc healing loot into secure container
- if (isPmc && PMCConfig.ForceHealingItemsIntoSecure)
+ if (botGenerationDetails.IsPmc && PMCConfig.ForceHealingItemsIntoSecure)
{
- AddForcedMedicalItemsToPmcSecure(botInventory, botRole, botId);
+ AddForcedMedicalItemsToPmcSecure(botInventory, botGenerationDetails.RoleLowercase, botId);
}
- var botItemLimits = GetItemSpawnLimitsForBot(botRole);
+ var botItemLimits = GetItemSpawnLimitsForBot(botGenerationDetails.RoleLowercase);
var containersBotHasAvailable = GetAvailableContainersBotCanStoreItemsIn(botInventory);
// Special items
AddLootFromPool(
botId,
- botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.Special, botJsonTemplate),
+ botLootCacheService.GetLootFromCache(
+ botGenerationDetails.RoleLowercase,
+ botGenerationDetails.IsPmc,
+ LootCacheType.Special,
+ botJsonTemplate
+ ),
containersBotHasAvailable,
specialLootItemCount,
botInventory,
- botRole,
+ botGenerationDetails.RoleLowercase,
botItemLimits
);
// Healing items / Meds
AddLootFromPool(
botId,
- botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.HealingItems, botJsonTemplate),
+ botLootCacheService.GetLootFromCache(
+ botGenerationDetails.RoleLowercase,
+ botGenerationDetails.IsPmc,
+ LootCacheType.HealingItems,
+ botJsonTemplate
+ ),
containersBotHasAvailable,
healingItemCount,
botInventory,
- botRole,
+ botGenerationDetails.RoleLowercase,
null,
0,
- isPmc
+ botGenerationDetails.IsPmc
);
// Drugs
AddLootFromPool(
botId,
- botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.DrugItems, botJsonTemplate),
+ botLootCacheService.GetLootFromCache(
+ botGenerationDetails.RoleLowercase,
+ botGenerationDetails.IsPmc,
+ LootCacheType.DrugItems,
+ botJsonTemplate
+ ),
containersBotHasAvailable,
drugItemCount,
botInventory,
- botRole,
+ botGenerationDetails.RoleLowercase,
null,
0,
- isPmc
+ botGenerationDetails.IsPmc
);
// Food
AddLootFromPool(
botId,
- botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.FoodItems, botJsonTemplate),
+ botLootCacheService.GetLootFromCache(
+ botGenerationDetails.RoleLowercase,
+ botGenerationDetails.IsPmc,
+ LootCacheType.FoodItems,
+ botJsonTemplate
+ ),
containersBotHasAvailable,
foodItemCount,
botInventory,
- botRole,
+ botGenerationDetails.RoleLowercase,
null,
0,
- isPmc
+ botGenerationDetails.IsPmc
);
// Drink
AddLootFromPool(
botId,
- botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.DrinkItems, botJsonTemplate),
+ botLootCacheService.GetLootFromCache(
+ botGenerationDetails.RoleLowercase,
+ botGenerationDetails.IsPmc,
+ LootCacheType.DrinkItems,
+ botJsonTemplate
+ ),
containersBotHasAvailable,
drinkItemCount,
botInventory,
- botRole,
+ botGenerationDetails.RoleLowercase,
null,
0,
- isPmc
+ botGenerationDetails.IsPmc
);
// Currency
AddLootFromPool(
botId,
- botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.CurrencyItems, botJsonTemplate),
+ botLootCacheService.GetLootFromCache(
+ botGenerationDetails.RoleLowercase,
+ botGenerationDetails.IsPmc,
+ LootCacheType.CurrencyItems,
+ botJsonTemplate
+ ),
containersBotHasAvailable,
currencyItemCount,
botInventory,
- botRole,
+ botGenerationDetails.RoleLowercase,
null,
0,
- isPmc
+ botGenerationDetails.IsPmc
);
// Stims
AddLootFromPool(
botId,
- botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.StimItems, botJsonTemplate),
+ botLootCacheService.GetLootFromCache(
+ botGenerationDetails.RoleLowercase,
+ botGenerationDetails.IsPmc,
+ LootCacheType.StimItems,
+ botJsonTemplate
+ ),
containersBotHasAvailable,
stimItemCount,
botInventory,
- botRole,
+ botGenerationDetails.RoleLowercase,
botItemLimits,
0,
- isPmc
+ botGenerationDetails.IsPmc
);
// Grenades
AddLootFromPool(
botId,
- botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.GrenadeItems, botJsonTemplate),
+ botLootCacheService.GetLootFromCache(
+ botGenerationDetails.RoleLowercase,
+ botGenerationDetails.IsPmc,
+ LootCacheType.GrenadeItems,
+ botJsonTemplate
+ ),
[EquipmentSlots.Pockets, EquipmentSlots.TacticalVest], // Can't use containersBotHasEquipped as we don't want grenades added to backpack
grenadeCount,
botInventory,
- botRole,
+ botGenerationDetails.RoleLowercase,
null,
0,
- isPmc
+ botGenerationDetails.IsPmc
);
- var itemPriceLimits = GetSingleItemLootPriceLimits(botLevel, isPmc);
+ var itemPriceLimits = GetSingleItemLootPriceLimits(botGenerationDetails.BotLevel, botGenerationDetails.IsPmc);
// Backpack - generate loot if they have one
if (containersBotHasAvailable.Contains(EquipmentSlots.Backpack) && backpackLootCount > 0)
{
// Add randomly generated weapon to PMC backpacks
- if (isPmc && randomUtil.GetChance100(PMCConfig.LooseWeaponInBackpackChancePercent))
+ if (botGenerationDetails.IsPmc && randomUtil.GetChance100(PMCConfig.LooseWeaponInBackpackChancePercent))
{
AddLooseWeaponsToInventorySlot(
botId,
sessionId,
botInventory,
EquipmentSlots.Backpack,
+ botGenerationDetails,
botJsonTemplate.BotInventory,
- botJsonTemplate.BotChances?.WeaponModsChances,
- botRole,
- isPmc,
- botLevel
+ botJsonTemplate.BotChances?.WeaponModsChances
);
}
- var backpackLootRoubleTotal = isPmc
- ? PMCConfig.LootSettings.Backpack.GetRoubleValue(botLevel, botGenerationDetails.Location)
+ var backpackLootRoubleTotal = botGenerationDetails.IsPmc
+ ? PMCConfig.LootSettings.Backpack.GetRoubleValue(botGenerationDetails.BotLevel, botGenerationDetails.Location)
: 0;
AddLootFromPool(
botId,
- botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.Backpack, botJsonTemplate, itemPriceLimits?.Backpack),
+ botLootCacheService.GetLootFromCache(
+ botGenerationDetails.RoleLowercase,
+ botGenerationDetails.IsPmc,
+ LootCacheType.Backpack,
+ botJsonTemplate,
+ itemPriceLimits?.Backpack
+ ),
[EquipmentSlots.Backpack],
backpackLootCount,
botInventory,
- botRole,
+ botGenerationDetails.RoleLowercase,
botItemLimits,
backpackLootRoubleTotal,
- isPmc
+ botGenerationDetails.IsPmc
);
}
- var vestLootRoubleTotal = isPmc ? PMCConfig.LootSettings.Vest.GetRoubleValue(botLevel, botGenerationDetails.Location) : 0;
+ var vestLootRoubleTotal = botGenerationDetails.IsPmc
+ ? PMCConfig.LootSettings.Vest.GetRoubleValue(botGenerationDetails.BotLevel, botGenerationDetails.Location)
+ : 0;
// TacticalVest - generate loot if they have one
if (containersBotHasAvailable.Contains(EquipmentSlots.TacticalVest))
@@ -276,47 +316,66 @@ public class BotLootGenerator(
{
AddLootFromPool(
botId,
- botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.Vest, botJsonTemplate, itemPriceLimits?.Vest),
+ botLootCacheService.GetLootFromCache(
+ botGenerationDetails.RoleLowercase,
+ botGenerationDetails.IsPmc,
+ LootCacheType.Vest,
+ botJsonTemplate,
+ itemPriceLimits?.Vest
+ ),
[EquipmentSlots.TacticalVest],
vestLootCount,
botInventory,
- botRole,
+ botGenerationDetails.RoleLowercase,
botItemLimits,
vestLootRoubleTotal,
- isPmc
+ botGenerationDetails.IsPmc
);
}
- var pocketLootRoubleTotal = isPmc ? PMCConfig.LootSettings.Pocket.GetRoubleValue(botLevel, botGenerationDetails.Location) : 0;
+ var pocketLootRoubleTotal = botGenerationDetails.IsPmc
+ ? PMCConfig.LootSettings.Pocket.GetRoubleValue(botGenerationDetails.BotLevel, botGenerationDetails.Location)
+ : 0;
// Pockets
AddLootFromPool(
botId,
- botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.Pocket, botJsonTemplate, itemPriceLimits?.Pocket),
+ botLootCacheService.GetLootFromCache(
+ botGenerationDetails.RoleLowercase,
+ botGenerationDetails.IsPmc,
+ LootCacheType.Pocket,
+ botJsonTemplate,
+ itemPriceLimits?.Pocket
+ ),
[EquipmentSlots.Pockets],
pocketLootCount,
botInventory,
- botRole,
+ botGenerationDetails.RoleLowercase,
botItemLimits,
pocketLootRoubleTotal,
- isPmc
+ botGenerationDetails.IsPmc
);
// Secure
// only add if not a pmc or is pmc and flag is true
- if (!isPmc || (isPmc && PMCConfig.AddSecureContainerLootFromBotConfig))
+ if (!botGenerationDetails.IsPmc || (botGenerationDetails.IsPmc && PMCConfig.AddSecureContainerLootFromBotConfig))
{
AddLootFromPool(
botId,
- botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.Secure, botJsonTemplate),
+ botLootCacheService.GetLootFromCache(
+ botGenerationDetails.RoleLowercase,
+ botGenerationDetails.IsPmc,
+ LootCacheType.Secure,
+ botJsonTemplate
+ ),
[EquipmentSlots.SecuredContainer],
50,
botInventory,
- botRole,
+ botGenerationDetails.RoleLowercase,
null,
-1,
- isPmc
+ botGenerationDetails.IsPmc
);
}
}
@@ -615,21 +674,17 @@ public class BotLootGenerator(
/// Session/Player id
/// Inventory to add preset to
/// Slot to place the preset in (backpack)
+ ///
/// Bots template, assault.json
/// Chances for mods to spawn on weapon
- /// bots role .e.g. pmcBot
- /// are we generating for a pmc
- /// Level of bot having loose weapon generated
public void AddLooseWeaponsToInventorySlot(
MongoId botId,
MongoId sessionId,
BotBaseInventory botInventory,
EquipmentSlots equipmentSlot,
+ BotGenerationDetails botGenerationDetails,
BotTypeInventory? templateInventory,
- Dictionary modChances,
- string botRole,
- bool isPmc,
- int botLevel
+ Dictionary modChances
)
{
var chosenWeaponType = randomUtil.GetArrayValue(
@@ -656,17 +711,17 @@ public class BotLootGenerator(
sessionId,
chosenWeaponType,
templateInventory,
+ botGenerationDetails,
botInventory.Equipment.Value,
- modChances,
- botRole,
- isPmc,
- botLevel
+ modChances
);
var weaponRootItem = generatedWeapon.Weapon?.FirstOrDefault();
if (weaponRootItem is null)
{
- logger.Error($"Generated null loose weapon: {chosenWeaponType} for: {botRole} level: {botLevel}, skipping");
+ logger.Error(
+ $"Generated null loose weapon: {chosenWeaponType} for: {botGenerationDetails.RoleLowercase} level: {botGenerationDetails.BotLevel}, skipping"
+ );
continue;
}
diff --git a/Libraries/SPTarkov.Server.Core/Generators/BotWeaponGenerator.cs b/Libraries/SPTarkov.Server.Core/Generators/BotWeaponGenerator.cs
index 74cdc4d5..51299a84 100644
--- a/Libraries/SPTarkov.Server.Core/Generators/BotWeaponGenerator.cs
+++ b/Libraries/SPTarkov.Server.Core/Generators/BotWeaponGenerator.cs
@@ -54,21 +54,17 @@ public class BotWeaponGenerator(
/// Session identifier
/// Primary/secondary/holster
/// e.g. assault.json
- ///
+ /// Details related to generating a bot
+ /// Details related to generating a bot
///
- /// Role of bot, e.g. assault/followerBully
- /// Is weapon generated for a pmc
- ///
/// GenerateWeaponResult object
public GenerateWeaponResult? GenerateRandomWeapon(
MongoId sessionId,
string equipmentSlot,
BotTypeInventory botTemplateInventory,
+ BotGenerationDetails botGenerationDetails,
MongoId weaponParentId,
- Dictionary modChances,
- string botRole,
- bool isPmc,
- int botLevel
+ Dictionary modChances
)
{
var weaponTpl = PickWeightedWeaponTemplateFromPool(equipmentSlot, botTemplateInventory);
@@ -79,9 +75,7 @@ public class BotWeaponGenerator(
botTemplateInventory,
weaponParentId,
modChances,
- botRole,
- isPmc,
- botLevel
+ botGenerationDetails
);
}
@@ -111,9 +105,7 @@ public class BotWeaponGenerator(
/// e.g. assault.json.
/// Parent ID of the weapon being generated.
/// Dictionary of item types and % chance weapon will have that mod.
- /// e.g. assault/exusec.
- /// Is weapon being generated for a PMC.
- /// The level of the bot.
+ ///
/// GenerateWeaponResult object.
public GenerateWeaponResult? GenerateWeaponByTpl(
MongoId sessionId,
@@ -122,9 +114,7 @@ public class BotWeaponGenerator(
BotTypeInventory botTemplateInventory,
MongoId weaponParentId,
Dictionary modChances,
- string botRole,
- bool isPmc,
- int botLevel
+ BotGenerationDetails botGenerationDetails
)
{
var modPool = botTemplateInventory.Mods;
@@ -141,17 +131,24 @@ public class BotWeaponGenerator(
// Find ammo to use when filling magazines/chamber
if (botTemplateInventory.Ammo is null)
{
- logger.Error(serverLocalisationService.GetText("bot-no_ammo_found_in_bot_json", botRole));
+ logger.Error(serverLocalisationService.GetText("bot-no_ammo_found_in_bot_json", botGenerationDetails.RoleLowercase));
logger.Error(serverLocalisationService.GetText("bot-generation_failed"));
}
var ammoTpl = GetWeightedCompatibleAmmo(botTemplateInventory.Ammo, weaponItemTemplate);
// Create with just base weapon item
- var weaponWithModsArray = ConstructWeaponBaseList(weaponTpl, weaponParentId, slotName, weaponItemTemplate, botRole).ToList();
+ var weaponWithModsArray = ConstructWeaponBaseList(
+ weaponTpl,
+ weaponParentId,
+ slotName,
+ weaponItemTemplate,
+ botGenerationDetails.RoleLowercase
+ )
+ .ToList();
// Chance to add randomised weapon enhancement
- if (isPmc && randomUtil.GetChance100(PMCConfig.WeaponHasEnhancementChancePercent))
+ if (botGenerationDetails.IsPmc && randomUtil.GetChance100(PMCConfig.WeaponHasEnhancementChancePercent))
// Add buff to weapon root
{
repairService.AddBuff(RepairConfig.RepairKit.Weapon, weaponWithModsArray[0]);
@@ -161,7 +158,7 @@ public class BotWeaponGenerator(
if (modPool.ContainsKey(weaponTpl))
{
// Role to treat bot as e.g. pmc/scav/boss
- var botEquipmentRole = botGeneratorHelper.GetBotEquipmentRole(botRole);
+ var botEquipmentRole = botGeneratorHelper.GetBotEquipmentRole(botGenerationDetails.RoleLowercase);
// Different limits if bot is boss vs scav
var modLimits = botWeaponModLimitService.GetWeaponModLimits(botEquipmentRole);
@@ -176,8 +173,8 @@ public class BotWeaponGenerator(
AmmoTpl = ammoTpl,
BotData = new BotData
{
- Role = botRole,
- Level = botLevel,
+ Role = botGenerationDetails.RoleLowercase,
+ Level = botGenerationDetails.BotLevel,
EquipmentRole = botEquipmentRole,
},
ModLimits = modLimits,
@@ -188,10 +185,16 @@ public class BotWeaponGenerator(
}
// Use weapon preset from globals.json if weapon isn't valid
- if (!IsWeaponValid(weaponWithModsArray, botRole))
+ if (!IsWeaponValid(weaponWithModsArray, botGenerationDetails.RoleLowercase))
// Weapon is bad, fall back to weapons preset
{
- weaponWithModsArray = GetPresetWeaponMods(weaponTpl, slotName, weaponParentId, weaponItemTemplate, botRole);
+ weaponWithModsArray = GetPresetWeaponMods(
+ weaponTpl,
+ slotName,
+ weaponParentId,
+ weaponItemTemplate,
+ botGenerationDetails.RoleLowercase
+ );
}
var tempList = cloner.Clone(weaponWithModsArray.Where(item => item.SlotId == ModMagazineSlotId));
@@ -708,10 +711,8 @@ public class BotWeaponGenerator(
// Try to get cartridges from slots array first, if none found, try Cartridges array
var cartridges =
- magazineTemplate.Value.Properties.Slots.FirstOrDefault()?.Properties?.Filters.FirstOrDefault()?.Filter ?? magazineTemplate
- .Value.Properties.Cartridges.FirstOrDefault()
- ?.Properties?.Filters.FirstOrDefault()
- ?.Filter;
+ magazineTemplate.Value.Properties.Slots.FirstOrDefault()?.Properties?.Filters.FirstOrDefault()?.Filter
+ ?? magazineTemplate.Value.Properties.Cartridges.FirstOrDefault()?.Properties?.Filters.FirstOrDefault()?.Filter;
return cartridges ?? [];
}
diff --git a/Libraries/SPTarkov.Server.Core/Models/Spt/Bots/BotGenerationDetails.cs b/Libraries/SPTarkov.Server.Core/Models/Spt/Bots/BotGenerationDetails.cs
index d0321a7c..33b7e008 100644
--- a/Libraries/SPTarkov.Server.Core/Models/Spt/Bots/BotGenerationDetails.cs
+++ b/Libraries/SPTarkov.Server.Core/Models/Spt/Bots/BotGenerationDetails.cs
@@ -17,6 +17,12 @@ public record BotGenerationDetails
[JsonPropertyName("role")]
public string Role { get; set; }
+ ///
+ /// assault/pmcBot etc
+ ///
+ [JsonPropertyName("BotRoleLowercase")]
+ public string RoleLowercase { get; set; }
+
///
/// Side of bot
///
@@ -85,4 +91,14 @@ public record BotGenerationDetails
///
[JsonPropertyName("clearBotContainerCacheAfterGeneration")]
public bool ClearBotContainerCacheAfterGeneration { get; set; } = true;
+
+ ///
+ /// Level the bot will have once generated
+ ///
+ public int BotLevel { get; set; }
+
+ ///
+ /// Version of the game bot will use - Only apples to PMCs
+ ///
+ public string GameVersion { get; set; }
}
diff --git a/Libraries/SPTarkov.Server.Core/Services/BotEquipmentFilterService.cs b/Libraries/SPTarkov.Server.Core/Services/BotEquipmentFilterService.cs
index db7e77a6..c8e9b5e2 100644
--- a/Libraries/SPTarkov.Server.Core/Services/BotEquipmentFilterService.cs
+++ b/Libraries/SPTarkov.Server.Core/Services/BotEquipmentFilterService.cs
@@ -28,22 +28,21 @@ public class BotEquipmentFilterService(
///
/// Players id
/// bots json data to filter
- /// Level of the bot
/// details on how to generate a bot
- public void FilterBotEquipment(MongoId sessionId, BotType baseBotNode, int botLevel, BotGenerationDetails botGenerationDetails)
+ public void FilterBotEquipment(MongoId sessionId, BotType baseBotNode, BotGenerationDetails botGenerationDetails)
{
var pmcProfile = profileHelper.GetPmcProfile(sessionId);
var botRole = botGenerationDetails.IsPmc ? "pmc" : botGenerationDetails.Role;
- var botEquipmentBlacklist = GetBotEquipmentBlacklist(botRole, botLevel);
- var botEquipmentWhitelist = GetBotEquipmentWhitelist(botRole, botLevel);
- var botWeightingAdjustments = GetBotWeightingAdjustments(botRole, botLevel);
+ var botEquipmentBlacklist = GetBotEquipmentBlacklist(botRole, botGenerationDetails.BotLevel);
+ var botEquipmentWhitelist = GetBotEquipmentWhitelist(botRole, botGenerationDetails.BotLevel);
+ var botWeightingAdjustments = GetBotWeightingAdjustments(botRole, botGenerationDetails.BotLevel);
var botWeightingAdjustmentsByPlayerLevel = GetBotWeightingAdjustmentsByPlayerLevel(botRole, pmcProfile?.Info?.Level ?? 1);
RandomisationDetails? randomisationDetails = null;
if (BotEquipmentConfig.TryGetValue(botRole.ToLowerInvariant(), out var botEquipmentConfig))
{
- randomisationDetails = botHelper.GetBotRandomizationDetails(botLevel, botEquipmentConfig);
+ randomisationDetails = botHelper.GetBotRandomizationDetails(botGenerationDetails.BotLevel, botEquipmentConfig);
}
if (botEquipmentBlacklist is not null || botEquipmentWhitelist is not null)
diff --git a/Libraries/SPTarkov.Server.Core/Services/BotNameService.cs b/Libraries/SPTarkov.Server.Core/Services/BotNameService.cs
index 12636aff..f8a99104 100644
--- a/Libraries/SPTarkov.Server.Core/Services/BotNameService.cs
+++ b/Libraries/SPTarkov.Server.Core/Services/BotNameService.cs
@@ -40,13 +40,11 @@ public class BotNameService(
///
/// bot JSON data from db
///
- /// role of bot e.g. assault
/// Lowercase roles to always make unique
/// Nickname for bot
public string GenerateUniqueBotNickname(
BotType botJsonTemplate,
BotGenerationDetails botGenerationDetails,
- string botRole,
HashSet? uniqueRoles = null
)
{
@@ -54,7 +52,7 @@ public class BotNameService(
// Never show for players
var showTypeInNickname = !botGenerationDetails.IsPlayerScav && BotConfig.ShowTypeInNickname;
- var roleShouldBeUnique = uniqueRoles?.Contains(botRole.ToLowerInvariant());
+ var roleShouldBeUnique = uniqueRoles?.Contains(botGenerationDetails.RoleLowercase);
var attempts = 0;
while (attempts <= 5)
@@ -69,7 +67,7 @@ public class BotNameService(
// Config is set to add role to end of bot name
if (showTypeInNickname)
{
- name += $" {botRole}";
+ name += $" {botGenerationDetails.RoleLowercase}";
}
// Replace pmc bot names with player name + prefix
@@ -93,7 +91,7 @@ public class BotNameService(
if (logger.IsLogEnabled(LogLevel.Debug))
{
logger.Debug(
- $"Failed to find unique name for: {botRole} {botGenerationDetails.Side} after 5 attempts, using: {genericName}"
+ $"Failed to find unique name for: {botGenerationDetails.RoleLowercase} {botGenerationDetails.Side} after 5 attempts, using: {genericName}"
);
}
@@ -114,7 +112,7 @@ public class BotNameService(
}
// Should never reach here
- return $"BOT {botRole} {botGenerationDetails.BotDifficulty}";
+ return $"BOT {botGenerationDetails.RoleLowercase} {botGenerationDetails.BotDifficulty}";
}
private bool AddNameToCache(string name)
diff --git a/Testing/UnitTests/Tests/Generators/BotWeaponGeneratorTests.cs b/Testing/UnitTests/Tests/Generators/BotWeaponGeneratorTests.cs
index 36a392e7..9fb8588b 100644
--- a/Testing/UnitTests/Tests/Generators/BotWeaponGeneratorTests.cs
+++ b/Testing/UnitTests/Tests/Generators/BotWeaponGeneratorTests.cs
@@ -3,6 +3,7 @@ using SPTarkov.Server.Core.Generators;
using SPTarkov.Server.Core.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Profile;
+using SPTarkov.Server.Core.Models.Spt.Bots;
using SPTarkov.Server.Core.Servers;
using SPTarkov.Server.Core.Services;
@@ -45,6 +46,13 @@ public class BotWeaponGeneratorTests
}
var weaponParentId = new MongoId();
+ var botGen = new BotGenerationDetails
+ {
+ Role = "pmcUSEC",
+ RoleLowercase = "pmcusec",
+ BotLevel = 69,
+ IsPmc = true,
+ };
for (var i = 0; i < 100; i++)
{
@@ -55,9 +63,7 @@ public class BotWeaponGeneratorTests
botTemplateInventory,
weaponParentId,
weaponModChances,
- "pmcUSEC",
- true,
- 69
+ botGen
);
var itemSize = _inventoryHelper.GetItemSize(weaponTpl, result.Weapon[0].Id, result.Weapon);