640 lines
26 KiB
C#
640 lines
26 KiB
C#
using Core.Annotations;
|
|
using Core.Context;
|
|
using Core.Helpers;
|
|
using Core.Models.Eft.Common.Tables;
|
|
using Core.Models.Eft.Match;
|
|
using Core.Models.Enums;
|
|
using Core.Models.Spt.Bots;
|
|
using Core.Models.Spt.Config;
|
|
using Core.Models.Utils;
|
|
using Core.Servers;
|
|
using Core.Services;
|
|
using Core.Utils;
|
|
using Equipment = Core.Models.Eft.Common.Tables.Equipment;
|
|
|
|
|
|
namespace Core.Generators;
|
|
|
|
[Injectable]
|
|
public class BotInventoryGenerator(
|
|
ISptLogger<BotInventoryGenerator> _logger,
|
|
HashUtil _hashUtil,
|
|
RandomUtil _randomUtil,
|
|
DatabaseService _databaseService,
|
|
ApplicationContext _applicationContext,
|
|
BotWeaponGenerator _botWeaponGenerator,
|
|
BotLootGenerator _botLootGenerator,
|
|
BotGeneratorHelper _botGeneratorHelper,
|
|
ProfileHelper _profileHelper,
|
|
BotHelper _botHelper,
|
|
WeightedRandomHelper _weightedRandomHelper,
|
|
ItemHelper _itemHelper,
|
|
WeatherHelper _weatherHelper,
|
|
LocalisationService _localisationService,
|
|
BotEquipmentFilterService _botEquipmentFilterService,
|
|
BotEquipmentModPoolService _botEquipmentModPoolService,
|
|
BotEquipmentModGenerator _botEquipmentModGenerator,
|
|
ConfigServer _configServer
|
|
)
|
|
{
|
|
private BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
|
|
|
|
/// <summary>
|
|
/// Add equipment/weapons/loot to bot
|
|
/// </summary>
|
|
/// <param name="sessionId">Session id</param>
|
|
/// <param name="botJsonTemplate">Base json db file for the bot having its loot generated</param>
|
|
/// <param name="botRole">Role bot has (assault/pmcBot)</param>
|
|
/// <param name="isPmc">Is bot being converted into a pmc</param>
|
|
/// <param name="botLevel">Level of bot being generated</param>
|
|
/// <param name="chosenGameVersion">Game version for bot, only really applies for PMCs</param>
|
|
/// <returns>PmcInventory object with equipment/weapons/loot</returns>
|
|
public BotBaseInventory GenerateInventory(string sessionId, BotType botJsonTemplate, string botRole, bool isPmc, int botLevel, string chosenGameVersion)
|
|
{
|
|
var templateInventory = botJsonTemplate.BotInventory;
|
|
var wornItemChances = botJsonTemplate.BotChances;
|
|
var itemGenerationLimitsMinMax = botJsonTemplate.BotGeneration;
|
|
|
|
// Generate base inventory with no items
|
|
var botInventory = GenerateInventoryBase();
|
|
|
|
// Get generated raid details bot will be spawned in
|
|
var raidConfig = _applicationContext
|
|
.GetLatestValue(ContextVariableType.RAID_CONFIGURATION)
|
|
?.GetValue<GetRaidConfigurationRequestData>();
|
|
|
|
GenerateAndAddEquipmentToBot(
|
|
sessionId,
|
|
templateInventory,
|
|
wornItemChances,
|
|
botRole,
|
|
botInventory,
|
|
botLevel,
|
|
chosenGameVersion,
|
|
raidConfig
|
|
);
|
|
|
|
// Roll weapon spawns (primary/secondary/holster) and generate a weapon for each roll that passed
|
|
GenerateAndAddWeaponsToBot(
|
|
templateInventory,
|
|
wornItemChances,
|
|
sessionId,
|
|
botInventory,
|
|
botRole,
|
|
isPmc,
|
|
itemGenerationLimitsMinMax,
|
|
botLevel
|
|
);
|
|
|
|
// Pick loot and add to bots containers (rig/backpack/pockets/secure)
|
|
_botLootGenerator.GenerateLoot(sessionId, botJsonTemplate, isPmc, botRole, botInventory, botLevel);
|
|
|
|
return botInventory;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create a pmcInventory object with all the base/generic items needed
|
|
/// </summary>
|
|
/// <returns>PmcInventory object</returns>
|
|
public BotBaseInventory GenerateInventoryBase()
|
|
{
|
|
var equipmentId = _hashUtil.Generate();
|
|
var stashId = _hashUtil.Generate();
|
|
var questRaidItemsId = _hashUtil.Generate();
|
|
var questStashItemsId = _hashUtil.Generate();
|
|
var sortingTableId = _hashUtil.Generate();
|
|
|
|
return new BotBaseInventory
|
|
{
|
|
Items =
|
|
[
|
|
new() { Id = equipmentId, Template = ItemTpl.INVENTORY_DEFAULT },
|
|
new() { Id = stashId, Template = ItemTpl.STASH_STANDARD_STASH_10X30 },
|
|
new() { Id = questRaidItemsId, Template = ItemTpl.STASH_QUESTRAID },
|
|
new() { Id = questStashItemsId, Template = ItemTpl.STASH_QUESTOFFLINE },
|
|
new() { Id = sortingTableId, Template = ItemTpl.SORTINGTABLE_SORTING_TABLE }
|
|
],
|
|
Equipment = equipmentId,
|
|
Stash = stashId,
|
|
QuestRaidItems = questRaidItemsId,
|
|
QuestStashItems = questStashItemsId,
|
|
SortingTable = sortingTableId,
|
|
HideoutAreaStashes = { },
|
|
FastPanel = { },
|
|
FavoriteItems = [],
|
|
HideoutCustomizationStashId = "",
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add equipment to a bot
|
|
/// </summary>
|
|
/// <param name="sessionId">Session id</param>
|
|
/// <param name="templateInventory">bot/x.json data from db</param>
|
|
/// <param name="wornItemChances">Chances items will be added to bot</param>
|
|
/// <param name="botRole">Role bot has (assault/pmcBot)</param>
|
|
/// <param name="botInventory">Inventory to add equipment to</param>
|
|
/// <param name="botLevel">Level of bot</param>
|
|
/// <param name="chosenGameVersion">Game version for bot, only really applies for PMCs</param>
|
|
/// <param name="raidConfig">RadiConfig</param>
|
|
public void GenerateAndAddEquipmentToBot(string sessionId, BotTypeInventory templateInventory, Chances wornItemChances, string botRole,
|
|
BotBaseInventory botInventory, int botLevel, string chosenGameVersion, GetRaidConfigurationRequestData raidConfig)
|
|
{
|
|
// These will be handled later
|
|
var excludedSlots = new List<EquipmentSlots>()
|
|
{
|
|
EquipmentSlots.Pockets,
|
|
EquipmentSlots.FirstPrimaryWeapon,
|
|
EquipmentSlots.SecondPrimaryWeapon,
|
|
EquipmentSlots.Holster,
|
|
EquipmentSlots.ArmorVest,
|
|
EquipmentSlots.TacticalVest,
|
|
EquipmentSlots.FaceCover,
|
|
EquipmentSlots.Headwear,
|
|
EquipmentSlots.Earpiece
|
|
};
|
|
|
|
_botConfig.Equipment.TryGetValue(_botGeneratorHelper.GetBotEquipmentRole(botRole), out var botEquipConfig);
|
|
var randomistionDetails = _botHelper.GetBotRandomizationDetails(botLevel, botEquipConfig);
|
|
|
|
// Apply nighttime changes if its nighttime + there's changes to make
|
|
if (
|
|
randomistionDetails?.NighttimeChanges is not null &&
|
|
raidConfig is not null &&
|
|
_weatherHelper.IsNightTime(raidConfig.TimeVariant)
|
|
)
|
|
{
|
|
foreach (var equipmentSlotKvP in (randomistionDetails.NighttimeChanges.EquipmentModsModifiers))
|
|
{
|
|
// Never let mod chance go outside of 0 - 100
|
|
randomistionDetails.EquipmentMods[equipmentSlotKvP.Key] = Math.Min(
|
|
Math.Max(randomistionDetails.EquipmentMods[equipmentSlotKvP.Key] + equipmentSlotKvP.Value, 0),
|
|
100
|
|
);
|
|
}
|
|
}
|
|
|
|
// Get profile of player generating bots, we use their level later on
|
|
var pmcProfile = _profileHelper.GetPmcProfile(sessionId);
|
|
var botEquipmentRole = _botGeneratorHelper.GetBotEquipmentRole(botRole);
|
|
|
|
|
|
// Iterate over all equipment slots of bot, do it in specifc order to reduce conflicts
|
|
// e.g. ArmorVest should be generated after TactivalVest
|
|
// or FACE_COVER before HEADWEAR
|
|
foreach (var (equipmentSlot, value) in templateInventory.Equipment)
|
|
{
|
|
// Skip some slots as they need to be done in a specific order + with specific parameter values
|
|
// e.g. Weapons
|
|
if (excludedSlots.Contains(equipmentSlot))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
GenerateEquipment(
|
|
new GenerateEquipmentProperties
|
|
{
|
|
RootEquipmentSlot = equipmentSlot,
|
|
RootEquipmentPool = value,
|
|
ModPool = templateInventory.Mods,
|
|
SpawnChances = wornItemChances,
|
|
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
|
Inventory = botInventory,
|
|
BotEquipmentConfig = botEquipConfig,
|
|
RandomisationDetails = randomistionDetails,
|
|
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
|
}
|
|
);
|
|
}
|
|
|
|
// Generate below in specific order
|
|
GenerateEquipment(
|
|
new GenerateEquipmentProperties
|
|
{
|
|
RootEquipmentSlot = EquipmentSlots.Pockets,
|
|
// Unheard profiles have unique sized pockets, TODO - handle this somewhere else in a better way
|
|
RootEquipmentPool =
|
|
chosenGameVersion == GameEditions.UNHEARD
|
|
? new Dictionary<string, double> { [ItemTpl.POCKETS_1X4_TUE] = 1 }
|
|
: templateInventory.Equipment[EquipmentSlots.Pockets],
|
|
ModPool = templateInventory.Mods,
|
|
SpawnChances = wornItemChances,
|
|
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
|
Inventory = botInventory,
|
|
BotEquipmentConfig = botEquipConfig,
|
|
RandomisationDetails = randomistionDetails,
|
|
GenerateModsBlacklist = [ItemTpl.POCKETS_1X4_TUE],
|
|
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
|
}
|
|
);
|
|
|
|
GenerateEquipment(
|
|
new GenerateEquipmentProperties
|
|
{
|
|
RootEquipmentSlot = EquipmentSlots.FaceCover,
|
|
RootEquipmentPool = templateInventory.Equipment[EquipmentSlots.FaceCover],
|
|
ModPool = templateInventory.Mods,
|
|
SpawnChances = wornItemChances,
|
|
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
|
Inventory = botInventory,
|
|
BotEquipmentConfig = botEquipConfig,
|
|
RandomisationDetails = randomistionDetails,
|
|
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
|
}
|
|
);
|
|
|
|
GenerateEquipment(
|
|
new GenerateEquipmentProperties
|
|
{
|
|
RootEquipmentSlot = EquipmentSlots.Headwear,
|
|
RootEquipmentPool = templateInventory.Equipment[EquipmentSlots.Headwear],
|
|
ModPool = templateInventory.Mods,
|
|
SpawnChances = wornItemChances,
|
|
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
|
Inventory = botInventory,
|
|
BotEquipmentConfig = botEquipConfig,
|
|
RandomisationDetails = randomistionDetails,
|
|
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
|
}
|
|
);
|
|
|
|
GenerateEquipment(
|
|
new GenerateEquipmentProperties
|
|
{
|
|
RootEquipmentSlot = EquipmentSlots.Earpiece,
|
|
RootEquipmentPool = templateInventory.Equipment[EquipmentSlots.Earpiece],
|
|
ModPool = templateInventory.Mods,
|
|
SpawnChances = wornItemChances,
|
|
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
|
Inventory = botInventory,
|
|
BotEquipmentConfig = botEquipConfig,
|
|
RandomisationDetails = randomistionDetails,
|
|
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
|
}
|
|
);
|
|
|
|
var hasArmorVest = GenerateEquipment(
|
|
new GenerateEquipmentProperties
|
|
{
|
|
RootEquipmentSlot = EquipmentSlots.ArmorVest,
|
|
RootEquipmentPool = templateInventory.Equipment[EquipmentSlots.ArmorVest],
|
|
ModPool = templateInventory.Mods,
|
|
SpawnChances = wornItemChances,
|
|
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
|
Inventory = botInventory,
|
|
BotEquipmentConfig = botEquipConfig,
|
|
RandomisationDetails = randomistionDetails,
|
|
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
|
}
|
|
);
|
|
|
|
// Bot has no armor vest and flagged to be forced to wear armored rig in this event
|
|
if (botEquipConfig.ForceOnlyArmoredRigWhenNoArmor.GetValueOrDefault(false) && !hasArmorVest)
|
|
{
|
|
// Filter rigs down to only those with armor
|
|
FilterRigsToThoseWithProtection(templateInventory.Equipment, botRole);
|
|
}
|
|
|
|
// Optimisation - Remove armored rigs from pool
|
|
if (hasArmorVest)
|
|
{
|
|
// Filter rigs down to only those with armor
|
|
FilterRigsToThoseWithoutProtection(templateInventory.Equipment, botRole);
|
|
}
|
|
|
|
// Bot is flagged as always needing a vest
|
|
if (botEquipConfig.ForceRigWhenNoVest.GetValueOrDefault(false) && !hasArmorVest)
|
|
{
|
|
wornItemChances.EquipmentChances["TacticalVest"] = 100;
|
|
}
|
|
|
|
GenerateEquipment(
|
|
new GenerateEquipmentProperties
|
|
{
|
|
RootEquipmentSlot = EquipmentSlots.Earpiece,
|
|
RootEquipmentPool = templateInventory.Equipment[EquipmentSlots.Earpiece],
|
|
ModPool = templateInventory.Mods,
|
|
SpawnChances = wornItemChances,
|
|
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
|
Inventory = botInventory,
|
|
BotEquipmentConfig = botEquipConfig,
|
|
RandomisationDetails = randomistionDetails,
|
|
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
|
}
|
|
);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove non-armored rigs from parameter data
|
|
/// </summary>
|
|
/// <param name="templateEquipment">Equpiment to filter TacticalVest of</param>
|
|
/// <param name="botRole">Role of bot vests are being filtered for</param>
|
|
public void FilterRigsToThoseWithProtection(Dictionary<EquipmentSlots, Dictionary<string, double>> templateEquipment, string botRole)
|
|
{
|
|
var tacVestsWithArmor = templateEquipment[EquipmentSlots.TacticalVest]
|
|
.Where(kvp => _itemHelper.ItemHasSlots(kvp.Key))
|
|
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
|
|
|
if (!tacVestsWithArmor.Any())
|
|
{
|
|
_logger.Debug($"Unable to filter to only armored rigs as bot: {botRole} has none in pool");
|
|
|
|
return;
|
|
}
|
|
|
|
templateEquipment[EquipmentSlots.TacticalVest] = tacVestsWithArmor;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove armored rigs from parameter data
|
|
/// </summary>
|
|
/// <param name="templateEquipment">Equipment to filter TacticalVest by</param>
|
|
/// <param name="botRole">Role of bot vests are being filtered for</param>
|
|
/// <param name="allowEmptyResult">Should the function return all rigs when 0 unarmored are found</param>
|
|
public void FilterRigsToThoseWithoutProtection(Dictionary<EquipmentSlots, Dictionary<string, double>> templateEquipment, string botRole,
|
|
bool allowEmptyResult = true)
|
|
{
|
|
var tacVestsWithoutArmor = templateEquipment[EquipmentSlots.TacticalVest]
|
|
.Where(kvp => !_itemHelper.ItemHasSlots(kvp.Key))
|
|
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
|
|
|
if (!allowEmptyResult && !tacVestsWithoutArmor.Any())
|
|
{
|
|
_logger.Debug($"Unable to filter to only unarmored rigs as bot: {botRole} has none in pool");
|
|
|
|
return;
|
|
}
|
|
|
|
templateEquipment[EquipmentSlots.TacticalVest] = tacVestsWithoutArmor;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add a piece of equipment with mods to inventory from the provided pools
|
|
/// </summary>
|
|
/// <param name="settings">Values to adjust how item is chosen and added to bot</param>
|
|
/// <returns>true when item added</returns>
|
|
public bool GenerateEquipment(GenerateEquipmentProperties settings)
|
|
{
|
|
List<string> slotsToCheck = [EquipmentSlots.Pockets.ToString(), EquipmentSlots.SecuredContainer.ToString()];
|
|
double? spawnChance = slotsToCheck.Contains(settings.RootEquipmentSlot.ToString())
|
|
? 100
|
|
: settings.SpawnChances.EquipmentChances.GetValueOrDefault(settings.RootEquipmentSlot.ToString());
|
|
|
|
if (!spawnChance.HasValue)
|
|
{
|
|
_logger.Warning(
|
|
_localisationService.GetText(
|
|
"bot-no_spawn_chance_defined_for_equipment_slot",
|
|
settings.RootEquipmentSlot
|
|
)
|
|
);
|
|
|
|
return false;
|
|
}
|
|
|
|
// Roll dice on equipment item
|
|
var shouldSpawn = _randomUtil.GetChance100(spawnChance ?? 0);
|
|
if (shouldSpawn && !settings.RootEquipmentPool.Any())
|
|
{
|
|
var pickedItemDb = new TemplateItem();
|
|
var found = false;
|
|
|
|
// Limit attempts to find a compatible item as it's expensive to check them all
|
|
var maxAttempts = Math.Round(settings.RootEquipmentPool.Count() * 0.75); // Roughly 75% of pool size
|
|
var attempts = 0;
|
|
while (!found)
|
|
{
|
|
if (!settings.RootEquipmentPool.Any())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var chosenItemTpl = _weightedRandomHelper.GetWeightedValue(settings.RootEquipmentPool);
|
|
var dbResult = _itemHelper.GetItem(chosenItemTpl);
|
|
|
|
if (!dbResult.Key)
|
|
{
|
|
_logger.Error(_localisationService.GetText("bot-missing_item_template", chosenItemTpl));
|
|
_logger.Debug($"EquipmentSlot-> {settings.RootEquipmentSlot}");
|
|
|
|
// Remove picked item
|
|
settings.RootEquipmentPool.Remove(chosenItemTpl);
|
|
|
|
attempts++;
|
|
|
|
continue;
|
|
}
|
|
|
|
// Is the chosen item compatible with other items equipped
|
|
var compatibilityResult = _botGeneratorHelper.IsItemIncompatibleWithCurrentItems(
|
|
settings.Inventory.Items,
|
|
chosenItemTpl,
|
|
settings.RootEquipmentSlot.ToString()
|
|
);
|
|
if (compatibilityResult.Incompatible ?? false)
|
|
{
|
|
// Tried x different items that failed, stop
|
|
if (attempts > maxAttempts)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Remove picked item from pool
|
|
settings.RootEquipmentPool.Remove(chosenItemTpl);
|
|
|
|
// Increment times tried
|
|
attempts++;
|
|
}
|
|
else
|
|
{
|
|
// Success
|
|
found = true;
|
|
pickedItemDb = dbResult.Value;
|
|
}
|
|
}
|
|
|
|
// Create root item
|
|
var id = _hashUtil.Generate();
|
|
Item item = new()
|
|
{
|
|
Id = id,
|
|
Template = pickedItemDb.Id,
|
|
ParentId = settings.Inventory.Equipment,
|
|
SlotId = settings.RootEquipmentSlot.ToString(),
|
|
Upd = _botGeneratorHelper.GenerateExtraPropertiesForItem(pickedItemDb, settings.BotData.Role)
|
|
};
|
|
|
|
var botEquipBlacklist = _botEquipmentFilterService.GetBotEquipmentBlacklist(
|
|
settings.BotData.EquipmentRole,
|
|
(double)settings.GeneratingPlayerLevel
|
|
);
|
|
|
|
// Edge case: Filter the armor items mod pool if bot exists in config dict + config has armor slot
|
|
if (_botConfig.Equipment[settings.BotData.EquipmentRole] is not null &&
|
|
settings.RandomisationDetails.RandomisedArmorSlots.Contains(settings.RootEquipmentSlot.ToString()))
|
|
{
|
|
// Filter out mods from relevant blacklist
|
|
settings.ModPool[pickedItemDb.Id] = GetFilteredDynamicModsForItem(
|
|
pickedItemDb.Id,
|
|
botEquipBlacklist.Equipment
|
|
);
|
|
}
|
|
|
|
// Does item have slots for sub-mods to be inserted into
|
|
if (pickedItemDb.Properties.Slots.Any() && settings.GenerateModsBlacklist.Contains(pickedItemDb.Id))
|
|
{
|
|
var childItemsToAdd = _botEquipmentModGenerator.GenerateModsForEquipment(
|
|
[item],
|
|
id,
|
|
pickedItemDb,
|
|
settings,
|
|
botEquipBlacklist
|
|
);
|
|
settings.Inventory.Items.AddRange(childItemsToAdd);
|
|
}
|
|
else
|
|
{
|
|
// No slots, add root item only
|
|
settings.Inventory.Items.Add(item);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get all possible mods for item and filter down based on equipment blacklist from bot.json config
|
|
/// </summary>
|
|
/// <param name="itemTpl">Item mod pool is being retrieved and filtered</param>
|
|
/// <param name="equipmentBlacklist">Blacklist to filter mod pool with</param>
|
|
/// <returns>Filtered pool of mods</returns>
|
|
public Dictionary<string, List<string>> GetFilteredDynamicModsForItem(string itemTpl, Dictionary<string, List<string>> equipmentBlacklist)
|
|
{
|
|
var modPool = _botEquipmentModPoolService.GetModsForGearSlot(itemTpl);
|
|
foreach (var modSlot in modPool.Keys ?? Enumerable.Empty<string>())
|
|
{
|
|
var blacklistedMods = equipmentBlacklist[modSlot] ?? [];
|
|
var filteredMods = modPool[modSlot].Where((slotName) => !blacklistedMods.Contains(slotName));
|
|
|
|
if (filteredMods.Any())
|
|
{
|
|
modPool[modSlot] = filteredMods.ToList();
|
|
}
|
|
}
|
|
|
|
return modPool;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Work out what weapons bot should have equipped and add them to bot inventory
|
|
/// </summary>
|
|
/// <param name="templateInventory">bot/x.json data from db</param>
|
|
/// <param name="equipmentChances">Chances bot can have equipment equipped</param>
|
|
/// <param name="sessionId">Session id</param>
|
|
/// <param name="botInventory">Inventory to add weapons to</param>
|
|
/// <param name="botRole">assault/pmcBot/bossTagilla etc</param>
|
|
/// <param name="isPmc">Is the bot being generated as a pmc</param>
|
|
/// <param name="itemGenerationLimitsMinMax">Limits for items the bot can have</param>
|
|
/// <param name="botLevel">level of bot having weapon generated</param>
|
|
public void GenerateAndAddWeaponsToBot(BotTypeInventory templateInventory, Chances equipmentChances, string sessionId, BotBaseInventory botInventory,
|
|
string botRole, bool isPmc, Generation itemGenerationLimitsMinMax, int botLevel)
|
|
{
|
|
var weaponSlotsToFill = GetDesiredWeaponsForBot(equipmentChances);
|
|
foreach (var desiredWeapons in weaponSlotsToFill)
|
|
{
|
|
// Add weapon to bot if true and bot json has something to put into the slot
|
|
if (desiredWeapons.ShouldSpawn && templateInventory.Equipment[desiredWeapons.Slot].Any())
|
|
{
|
|
AddWeaponAndMagazinesToInventory(
|
|
sessionId,
|
|
desiredWeapons,
|
|
templateInventory,
|
|
botInventory,
|
|
equipmentChances,
|
|
botRole,
|
|
isPmc,
|
|
itemGenerationLimitsMinMax,
|
|
botLevel
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculate if the bot should have weapons in Primary/Secondary/Holster slots
|
|
/// </summary>
|
|
/// <param name="equipmentChances">Chances bot has certain equipment</param>
|
|
/// <returns>What slots bot should have weapons generated for</returns>
|
|
public List<DesiredWeapons> GetDesiredWeaponsForBot(Chances equipmentChances)
|
|
{
|
|
var shouldSpawnPrimary = _randomUtil.GetChance100(equipmentChances.EquipmentChances["FirstPrimaryWeapon"]);
|
|
return
|
|
[
|
|
new()
|
|
{
|
|
Slot = EquipmentSlots.FirstPrimaryWeapon, ShouldSpawn = shouldSpawnPrimary
|
|
},
|
|
new()
|
|
{
|
|
Slot = EquipmentSlots.SecondPrimaryWeapon,
|
|
ShouldSpawn = shouldSpawnPrimary
|
|
? _randomUtil.GetChance100(equipmentChances.EquipmentChances["SecondPrimaryWeapon"])
|
|
: false
|
|
},
|
|
new()
|
|
{
|
|
Slot = EquipmentSlots.Holster,
|
|
ShouldSpawn = shouldSpawnPrimary
|
|
? _randomUtil.GetChance100(equipmentChances.EquipmentChances["Holster"]) // Primary weapon = roll for chance at pistol
|
|
: true // No primary = force pistol
|
|
}
|
|
];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add weapon + spare mags/ammo to bots inventory
|
|
/// </summary>
|
|
/// <param name="sessionId">Session id</param>
|
|
/// <param name="weaponSlot">Weapon slot being generated</param>
|
|
/// <param name="templateInventory">bot/x.json data from db</param>
|
|
/// <param name="botInventory">Inventory to add weapon+mags/ammo to</param>
|
|
/// <param name="equipmentChances">Chances bot can have equipment equipped</param>
|
|
/// <param name="botRole">assault/pmcBot/bossTagilla etc</param>
|
|
/// <param name="isPmc">Is the bot being generated as a pmc</param>
|
|
/// <param name="itemGenerationWeights"></param>
|
|
/// <param name="botLevel"></param>
|
|
public void AddWeaponAndMagazinesToInventory(string sessionId, DesiredWeapons weaponSlot, BotTypeInventory templateInventory, BotBaseInventory botInventory,
|
|
Chances equipmentChances, string botRole,
|
|
bool isPmc, Generation itemGenerationWeights, int botLevel)
|
|
{
|
|
var generatedWeapon = _botWeaponGenerator.GenerateRandomWeapon(
|
|
sessionId,
|
|
weaponSlot.Slot.ToString(),
|
|
templateInventory,
|
|
botInventory.Equipment,
|
|
equipmentChances.WeaponModsChances,
|
|
botRole,
|
|
isPmc,
|
|
botLevel
|
|
);
|
|
|
|
botInventory.Items.AddRange(generatedWeapon.Weapon);
|
|
|
|
_botWeaponGenerator.AddExtraMagazinesToInventory(
|
|
generatedWeapon,
|
|
itemGenerationWeights.Items.Magazines,
|
|
botInventory,
|
|
botRole
|
|
);
|
|
}
|
|
}
|
|
|
|
public class DesiredWeapons
|
|
{
|
|
public EquipmentSlots Slot { get; set; }
|
|
|
|
public bool ShouldSpawn { get; set; }
|
|
}
|