Merge branch 'main' of https://github.com/sp-tarkov/server-csharp
This commit is contained in:
@@ -145,7 +145,8 @@ public class BotInventoryGenerator
|
||||
var questStashItemsId = _hashUtil.Generate();
|
||||
var sortingTableId = _hashUtil.Generate();
|
||||
|
||||
return new BotBaseInventory{
|
||||
return new BotBaseInventory
|
||||
{
|
||||
Items =
|
||||
[
|
||||
new() { Id = equipmentId, Template = ItemTpl.INVENTORY_DEFAULT },
|
||||
@@ -181,7 +182,8 @@ public class BotInventoryGenerator
|
||||
BotBaseInventory botInventory, int botLevel, string chosenGameVersion, GetRaidConfigurationRequestData raidConfig)
|
||||
{
|
||||
// These will be handled later
|
||||
var excludedSlots = new List<EquipmentSlots>(){
|
||||
var excludedSlots = new List<EquipmentSlots>()
|
||||
{
|
||||
EquipmentSlots.Pockets,
|
||||
EquipmentSlots.FirstPrimaryWeapon,
|
||||
EquipmentSlots.SecondPrimaryWeapon,
|
||||
@@ -203,10 +205,11 @@ public class BotInventoryGenerator
|
||||
_weatherHelper.IsNightTime(raidConfig.TimeVariant)
|
||||
)
|
||||
{
|
||||
foreach (var equipmentSlotKvP in (randomistionDetails.NighttimeChanges.EquipmentModsModifiers)) {
|
||||
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);
|
||||
Math.Max(randomistionDetails.EquipmentMods[equipmentSlotKvP.Key] + equipmentSlotKvP.Value, 0), 100);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,14 +221,16 @@ public class BotInventoryGenerator
|
||||
// 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 equipmentSlotKvP in templateInventory.Equipment) {
|
||||
foreach (var equipmentSlotKvP 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(equipmentSlotKvP.Key)) {
|
||||
if (excludedSlots.Contains(equipmentSlotKvP.Key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
GenerateEquipment( new GenerateEquipmentProperties
|
||||
GenerateEquipment(new GenerateEquipmentProperties
|
||||
{
|
||||
RootEquipmentSlot = equipmentSlotKvP.Key,
|
||||
RootEquipmentPool = equipmentSlotKvP.Value,
|
||||
@@ -240,17 +245,17 @@ public class BotInventoryGenerator
|
||||
}
|
||||
|
||||
// Generate below in specific order
|
||||
GenerateEquipment( new GenerateEquipmentProperties
|
||||
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 }
|
||||
? 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 },
|
||||
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
||||
Inventory = botInventory,
|
||||
BotEquipmentConfig = botEquipConfig,
|
||||
RandomisationDetails = randomistionDetails,
|
||||
@@ -258,7 +263,7 @@ public class BotInventoryGenerator
|
||||
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
||||
});
|
||||
|
||||
GenerateEquipment( new GenerateEquipmentProperties
|
||||
GenerateEquipment(new GenerateEquipmentProperties
|
||||
{
|
||||
RootEquipmentSlot = EquipmentSlots.FaceCover,
|
||||
RootEquipmentPool = templateInventory.Equipment[EquipmentSlots.FaceCover],
|
||||
@@ -271,7 +276,7 @@ public class BotInventoryGenerator
|
||||
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
||||
});
|
||||
|
||||
GenerateEquipment( new GenerateEquipmentProperties
|
||||
GenerateEquipment(new GenerateEquipmentProperties
|
||||
{
|
||||
RootEquipmentSlot = EquipmentSlots.Headwear,
|
||||
RootEquipmentPool = templateInventory.Equipment[EquipmentSlots.Headwear],
|
||||
@@ -297,7 +302,7 @@ public class BotInventoryGenerator
|
||||
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
||||
});
|
||||
|
||||
var hasArmorVest = GenerateEquipment( new GenerateEquipmentProperties
|
||||
var hasArmorVest = GenerateEquipment(new GenerateEquipmentProperties
|
||||
{
|
||||
RootEquipmentSlot = EquipmentSlots.ArmorVest,
|
||||
RootEquipmentPool = templateInventory.Equipment[EquipmentSlots.ArmorVest],
|
||||
@@ -311,23 +316,26 @@ public class BotInventoryGenerator
|
||||
});
|
||||
|
||||
// Bot has no armor vest and flagged to be forced to wear armored rig in this event
|
||||
if (botEquipConfig.ForceOnlyArmoredRigWhenNoArmor.GetValueOrDefault(false) && !hasArmorVest) {
|
||||
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) {
|
||||
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) {
|
||||
if (botEquipConfig.ForceRigWhenNoVest.GetValueOrDefault(false) && !hasArmorVest)
|
||||
{
|
||||
wornItemChances.EquipmentChances["TacticalVest"] = 100;
|
||||
}
|
||||
|
||||
GenerateEquipment( new GenerateEquipmentProperties
|
||||
GenerateEquipment(new GenerateEquipmentProperties
|
||||
{
|
||||
RootEquipmentSlot = EquipmentSlots.Earpiece,
|
||||
RootEquipmentPool = templateInventory.Equipment[EquipmentSlots.Earpiece],
|
||||
@@ -348,12 +356,17 @@ public class BotInventoryGenerator
|
||||
/// <param name="botRole">Role of bot vests are being filtered for</param>
|
||||
public void FilterRigsToThoseWithProtection(Dictionary<EquipmentSlots, Dictionary<string, double>> templateEquipment, string botRole)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void FilterRigsToThoseWithoutProtection(Dictionary<EquipmentSlots, Dictionary<string, double>> templateEquipment, string botRole, bool allowEmptyResult = true)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var tacVestsWithArmor = templateEquipment[EquipmentSlots.TacticalVest].Where(kvp => _itemHelper.ItemHasSlots(kvp.Key))
|
||||
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||
|
||||
if (tacVestsWithArmor.Count() == 0)
|
||||
{
|
||||
_logger.Debug($"Unable to filter to only armored rigs as bot: {botRole} has none in pool");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
templateEquipment[EquipmentSlots.TacticalVest] = tacVestsWithArmor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -362,9 +375,20 @@ public class BotInventoryGenerator
|
||||
/// <param name="templateEquipment">Equpiment to filter TacticalVest of</param>
|
||||
/// <param name="botRole">Role of bot vests are being filtered for</param>
|
||||
/// <param name="allowEmptyRequest">Should the function return all rigs when 0 unarmored are found</param>
|
||||
public void FilterRigsTothoseWithoutProtection(Equipment templateEquipment, string botRole, bool allowEmptyRequest = false)
|
||||
public void FilterRigsToThoseWithoutProtection(Dictionary<EquipmentSlots, Dictionary<string, double>> templateEquipment, string botRole,
|
||||
bool allowEmptyResult = true)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var tacVestsWithoutArmor = templateEquipment[EquipmentSlots.TacticalVest].Where(kvp => !_itemHelper.ItemHasSlots(kvp.Key))
|
||||
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||
|
||||
if (!allowEmptyResult && tacVestsWithoutArmor.Count() == 0)
|
||||
{
|
||||
_logger.Debug($"Unable to filter to only unarmored rigs as bot: {botRole} has none in pool");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
templateEquipment[EquipmentSlots.TacticalVest] = tacVestsWithoutArmor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -375,7 +399,129 @@ public class BotInventoryGenerator
|
||||
public bool GenerateEquipment(GenerateEquipmentProperties settings)
|
||||
{
|
||||
_logger.Error("NOT IMPLEMENTED - GenerateEquipment");
|
||||
return true;
|
||||
List<string> slotsToCheck = [EquipmentSlots.Pockets.ToString(), EquipmentSlots.SecuredContainer.ToString()];
|
||||
double? spawnChance = slotsToCheck.Contains(settings.RootEquipmentSlot.ToString())
|
||||
? 100
|
||||
: settings.SpawnChances.EquipmentChances[settings.RootEquipmentSlot.ToString()];
|
||||
|
||||
if (spawnChance is null)
|
||||
{
|
||||
_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.Count() == 0)
|
||||
{
|
||||
TemplateItem pickedItemDb = new TemplateItem();
|
||||
var found = false;
|
||||
|
||||
// Limit attempts to find a compatible item as its 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.Count() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var chosenItemTpl = _weightedRandomHelper.GetWeightedValue<string>(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?.Count() > 0 && (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>
|
||||
@@ -386,7 +532,19 @@ public class BotInventoryGenerator
|
||||
/// <returns>Filtered pool of mods</returns>
|
||||
public Dictionary<string, List<string>> GetFilteredDynamicModsForItem(string itemTpl, Dictionary<string, List<string>> equipmentBlacklist)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
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.Count() > 0)
|
||||
{
|
||||
modPool[modSlot] = filteredMods.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
return modPool;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -401,10 +559,27 @@ public class BotInventoryGenerator
|
||||
/// <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)
|
||||
string botRole, bool isPmc, Generation itemGenerationLimitsMinMax, int botLevel)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var weaponSlotsToFill = GetDesiredWeaponsForBot(equipmentChances);
|
||||
foreach (var weaponSlot in weaponSlotsToFill)
|
||||
{
|
||||
// Add weapon to bot if true and bot json has something to put into the slot
|
||||
if (weaponSlot.ShouldSpawn && templateInventory.Equipment[weaponSlot.Slot].Any())
|
||||
{
|
||||
AddWeaponAndMagazinesToInventory(
|
||||
sessionId,
|
||||
weaponSlot,
|
||||
templateInventory,
|
||||
botInventory,
|
||||
equipmentChances,
|
||||
botRole,
|
||||
isPmc,
|
||||
itemGenerationLimitsMinMax,
|
||||
botLevel
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -412,9 +587,30 @@ public class BotInventoryGenerator
|
||||
/// </summary>
|
||||
/// <param name="equipmentChances">Chances bot has certain equipment</param>
|
||||
/// <returns>What slots bot should have weapons generated for</returns>
|
||||
public object GetDesiredWeaponsForBot(Chances equipmentChances) // TODO: Type fuckery { slot: EquipmentSlots; shouldSpawn: boolean }[]
|
||||
public List<DesiredWeapons> GetDesiredWeaponsForBot(Chances equipmentChances) // TODO: Type fuckery { slot: EquipmentSlots; shouldSpawn: boolean }[]
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
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>
|
||||
@@ -429,10 +625,34 @@ public class BotInventoryGenerator
|
||||
/// <param name="isPmc">Is the bot being generated as a pmc</param>
|
||||
/// <param name="itemGenerationWeights"></param>
|
||||
/// <param name="botLevel"></param>
|
||||
public void AddWeaponAndMagazineToInventory(string sessionId, object weaponSlot, BotBaseInventory templateInventory, BotBaseInventory botInventory,
|
||||
public void AddWeaponAndMagazinesToInventory(string sessionId, DesiredWeapons weaponSlot, BotTypeInventory templateInventory, BotBaseInventory botInventory,
|
||||
Chances equipmentChances, string botRole,
|
||||
bool isPmc, Generation itemGenerationWeights, int botLevel)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
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; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user