FixieWixie
This commit is contained in:
@@ -37,7 +37,8 @@ public class BotEquipmentModGenerator(
|
||||
BotEquipmentModPoolService _botEquipmentModPoolService,
|
||||
ConfigServer _configServer,
|
||||
ICloner _cloner
|
||||
) {
|
||||
)
|
||||
{
|
||||
protected BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
|
||||
|
||||
/// <summary>
|
||||
@@ -51,23 +52,28 @@ public class BotEquipmentModGenerator(
|
||||
/// <param name="shouldForceSpawn">should this mod be forced to spawn</param>
|
||||
/// <returns>Item + compatible mods as an array</returns>
|
||||
public List<Item> GenerateModsForEquipment(List<Item> equipment, string parentId, TemplateItem parentTemplate, GenerateEquipmentProperties settings,
|
||||
EquipmentFilterDetails specificBlacklist, bool shouldForceSpawn = false) {
|
||||
EquipmentFilterDetails specificBlacklist, bool shouldForceSpawn = false)
|
||||
{
|
||||
var forceSpawn = shouldForceSpawn;
|
||||
|
||||
// Get mod pool for the desired item
|
||||
if (!settings.ModPool.TryGetValue(parentTemplate.Id, out var compatibleModsPool)) {
|
||||
if (!settings.ModPool.TryGetValue(parentTemplate.Id, out var compatibleModsPool))
|
||||
{
|
||||
_logger.Warning($"bot: {settings.BotData.Role} lacks a mod slot pool for item: {parentTemplate.Id} {parentTemplate.Name}");
|
||||
}
|
||||
|
||||
// Iterate over mod pool and choose mods to add to item
|
||||
foreach (var (modSlotName, modPool) in compatibleModsPool ?? []) {
|
||||
foreach (var (modSlotName, modPool) in compatibleModsPool ?? [])
|
||||
{
|
||||
// Get the templates slot object from db
|
||||
var itemSlotTemplate = GetModItemSlotFromDb(modSlotName, parentTemplate);
|
||||
if (itemSlotTemplate is null) {
|
||||
if (itemSlotTemplate is null)
|
||||
{
|
||||
_logger.Error(
|
||||
_localisationService.GetText(
|
||||
"bot-mod_slot_missing_from_item",
|
||||
new {
|
||||
new
|
||||
{
|
||||
modSlot = modSlotName,
|
||||
parentId = parentTemplate.Id,
|
||||
parentName = parentTemplate.Name,
|
||||
@@ -87,12 +93,14 @@ public class BotEquipmentModGenerator(
|
||||
);
|
||||
|
||||
// Rolled to skip mod and it shouldn't be force-spawned
|
||||
if (modSpawnResult == ModSpawn.SKIP && !forceSpawn) {
|
||||
if (modSpawnResult == ModSpawn.SKIP && !forceSpawn)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ensure submods for nvgs all spawn together
|
||||
if (modSlotName == "mod_nvg") {
|
||||
if (modSlotName == "mod_nvg")
|
||||
{
|
||||
forceSpawn = true;
|
||||
}
|
||||
|
||||
@@ -101,7 +109,8 @@ public class BotEquipmentModGenerator(
|
||||
|
||||
// Filter the pool of items in blacklist
|
||||
var filteredModPool = FilterModsByBlacklist(modPoolToChooseFrom, specificBlacklist, modSlotName);
|
||||
if (filteredModPool.Count > 0) {
|
||||
if (filteredModPool.Count > 0)
|
||||
{
|
||||
// use filtered pool as it has items in it
|
||||
modPoolToChooseFrom = filteredModPool;
|
||||
}
|
||||
@@ -110,14 +119,16 @@ public class BotEquipmentModGenerator(
|
||||
if (
|
||||
settings.BotEquipmentConfig.FilterPlatesByLevel.GetValueOrDefault(false) &&
|
||||
_itemHelper.IsRemovablePlateSlot(modSlotName.ToLower())
|
||||
) {
|
||||
)
|
||||
{
|
||||
var plateSlotFilteringOutcome = FilterPlateModsForSlotByLevel(
|
||||
settings,
|
||||
modSlotName.ToLower(),
|
||||
compatibleModsPool[modSlotName],
|
||||
parentTemplate
|
||||
);
|
||||
switch (plateSlotFilteringOutcome.Result) {
|
||||
switch (plateSlotFilteringOutcome.Result)
|
||||
{
|
||||
case Result.UNKNOWN_FAILURE or Result.NO_DEFAULT_FILTER:
|
||||
_logger.Debug(
|
||||
$"Plate slot: {modSlotName} selection for armor: {parentTemplate.Id} failed: {plateSlotFilteringOutcome.Result}, skipping"
|
||||
@@ -139,23 +150,27 @@ public class BotEquipmentModGenerator(
|
||||
string modTpl = null;
|
||||
var found = false;
|
||||
var exhaustableModPool = CreateExhaustableArray(modPoolToChooseFrom.ToList());
|
||||
while (exhaustableModPool.HasValues()) {
|
||||
while (exhaustableModPool.HasValues())
|
||||
{
|
||||
modTpl = exhaustableModPool.GetRandomValue();
|
||||
if (modTpl is not null &&
|
||||
!_botGeneratorHelper.IsItemIncompatibleWithCurrentItems(equipment, modTpl, modSlotName).Incompatible.GetValueOrDefault(false)) {
|
||||
!_botGeneratorHelper.IsItemIncompatibleWithCurrentItems(equipment, modTpl, modSlotName).Incompatible.GetValueOrDefault(false))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Compatible item not found but slot REQUIRES item, get random item from db
|
||||
if (!found && itemSlotTemplate.Required.GetValueOrDefault(false)) {
|
||||
if (!found && itemSlotTemplate.Required.GetValueOrDefault(false))
|
||||
{
|
||||
modTpl = GetRandomModTplFromItemDb(modTpl, itemSlotTemplate, modSlotName, equipment);
|
||||
found = modTpl is not null;
|
||||
}
|
||||
|
||||
// Compatible item not found + not required - skip
|
||||
if (!(found || itemSlotTemplate.Required.GetValueOrDefault(false))) {
|
||||
if (!(found || itemSlotTemplate.Required.GetValueOrDefault(false)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -169,7 +184,8 @@ public class BotEquipmentModGenerator(
|
||||
parentTemplate,
|
||||
settings.BotData.Role
|
||||
)
|
||||
) {
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -180,7 +196,8 @@ public class BotEquipmentModGenerator(
|
||||
);
|
||||
|
||||
// Does item being added exist in mod pool - has its own mod pool
|
||||
if (settings.ModPool.ContainsKey(modTpl)) {
|
||||
if (settings.ModPool.ContainsKey(modTpl))
|
||||
{
|
||||
// Call self again with mod being added as item to add child mods to
|
||||
GenerateModsForEquipment(
|
||||
equipment,
|
||||
@@ -205,14 +222,17 @@ public class BotEquipmentModGenerator(
|
||||
/// <param name="armorItem">The armor items db template</param>
|
||||
/// <returns>Array of plate tpls to choose from</returns>
|
||||
public FilterPlateModsForSlotByLevelResult FilterPlateModsForSlotByLevel(GenerateEquipmentProperties settings, string modSlot,
|
||||
HashSet<string> existingPlateTplPool, TemplateItem armorItem) {
|
||||
var result = new FilterPlateModsForSlotByLevelResult {
|
||||
HashSet<string> existingPlateTplPool, TemplateItem armorItem)
|
||||
{
|
||||
var result = new FilterPlateModsForSlotByLevelResult
|
||||
{
|
||||
Result = Result.UNKNOWN_FAILURE,
|
||||
PlateModTemplates = null,
|
||||
};
|
||||
|
||||
// Not pmc or not a plate slot, return original mod pool array
|
||||
if (!_itemHelper.IsRemovablePlateSlot(modSlot)) {
|
||||
if (!_itemHelper.IsRemovablePlateSlot(modSlot))
|
||||
{
|
||||
result.Result = Result.NOT_PLATE_HOLDING_SLOT;
|
||||
result.PlateModTemplates = existingPlateTplPool;
|
||||
|
||||
@@ -224,8 +244,10 @@ public class BotEquipmentModGenerator(
|
||||
(armorWeight) =>
|
||||
settings.BotData.Level >= armorWeight.LevelRange.Min &&
|
||||
settings.BotData.Level <= armorWeight.LevelRange.Max
|
||||
);
|
||||
if (plateSlotWeights is null) {
|
||||
);
|
||||
|
||||
if (plateSlotWeights is null)
|
||||
{
|
||||
// No weights, return original array of plate tpls
|
||||
result.Result = Result.LACKS_PLATE_WEIGHTS;
|
||||
result.PlateModTemplates = existingPlateTplPool;
|
||||
@@ -235,7 +257,8 @@ public class BotEquipmentModGenerator(
|
||||
|
||||
// Get the specific plate slot weights (front/back/side)
|
||||
var plateWeights = plateSlotWeights[modSlot];
|
||||
if (plateWeights is null) {
|
||||
if (plateWeights is null)
|
||||
{
|
||||
// No weights, return original array of plate tpls
|
||||
result.Result = Result.LACKS_PLATE_WEIGHTS;
|
||||
result.PlateModTemplates = existingPlateTplPool;
|
||||
@@ -251,7 +274,8 @@ public class BotEquipmentModGenerator(
|
||||
|
||||
// Filter plates to the chosen level based on its armorClass property
|
||||
var platesOfDesiredLevel = platesFromDb.Filter((item) => item._props.armorClass == chosenArmorPlateLevel);
|
||||
if (platesOfDesiredLevel.length > 0) {
|
||||
if (platesOfDesiredLevel.length > 0)
|
||||
{
|
||||
// Plates found
|
||||
result.Result = Result.SUCCESS;
|
||||
result.PlateModTemplates = platesOfDesiredLevel.map((item) => item._id);
|
||||
@@ -262,65 +286,73 @@ public class BotEquipmentModGenerator(
|
||||
// no plates found that fit requirements, lets get creative
|
||||
|
||||
// Get lowest and highest plate classes available for this armor
|
||||
const minMaxArmorPlateClass = this.getMinMaxArmorPlateClass(platesFromDb);
|
||||
const minMaxArmorPlateClass = this.getMinMaxArmorPlateClass(platesFromDb);
|
||||
|
||||
// Increment plate class level in attempt to get useable plate
|
||||
let findCompatiblePlateAttempts = 0;
|
||||
const maxAttempts = 3;
|
||||
for (let i = 0; i < maxAttempts; i++) {
|
||||
const maxAttempts = 3;
|
||||
for (let i = 0; i < maxAttempts; i++)
|
||||
{
|
||||
chosenArmorPlateLevel = (Number.parseInt(chosenArmorPlateLevel) + 1).toString();
|
||||
|
||||
// New chosen plate class is higher than max, then set to min and check if valid
|
||||
if (Number(chosenArmorPlateLevel) > minMaxArmorPlateClass.max) {
|
||||
if (Number(chosenArmorPlateLevel) > minMaxArmorPlateClass.max)
|
||||
{
|
||||
chosenArmorPlateLevel = minMaxArmorPlateClass.min.toString();
|
||||
}
|
||||
|
||||
findCompatiblePlateAttempts++;
|
||||
|
||||
platesOfDesiredLevel = platesFromDb.filter((item) => item._props.armorClass === chosenArmorPlateLevel);
|
||||
platesOfDesiredLevel = platesFromDb.filter((item) => item._props.armorClass == = chosenArmorPlateLevel);
|
||||
// Valid plates found, exit
|
||||
if (platesOfDesiredLevel.length > 0) {
|
||||
if (platesOfDesiredLevel.length > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// No valid plate class found in 3 tries, attempt default plates
|
||||
if (findCompatiblePlateAttempts >= maxAttempts) {
|
||||
if (findCompatiblePlateAttempts >= maxAttempts)
|
||||
{
|
||||
this.logger.debug(
|
||||
`Plate filter too restrictive for armor: ${ armorItem._name} ${ armorItem._id}, unable to find plates of level: ${ chosenArmorPlateLevel}, using items default plate`,
|
||||
$"Plate filter too restrictive for armor: ${{ armorItem._name}} ${{ armorItem._id}}, unable to find plates of level: ${{ chosenArmorPlateLevel}}, using items default plate"
|
||||
);
|
||||
|
||||
const defaultPlate = this.getDefaultPlateTpl(armorItem, modSlot);
|
||||
if (defaultPlate) {
|
||||
// Return Default Plates cause couldn't get lowest level available from original selection
|
||||
result.result = Result.SUCCESS;
|
||||
result.plateModTpls = [defaultPlate];
|
||||
const defaultPlate = this.getDefaultPlateTpl(armorItem, modSlot);
|
||||
if (defaultPlate)
|
||||
{
|
||||
// Return Default Plates cause couldn't get lowest level available from original selection
|
||||
result.result = Result.SUCCESS;
|
||||
result.plateModTpls = [defaultPlate];
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
// No plate found after filtering AND no default plate
|
||||
|
||||
// Last attempt, get default preset and see if it has a plate default
|
||||
const defaultPresetPlateSlot = this.getDefaultPresetArmorSlot(armorItem._id, modSlot);
|
||||
if (defaultPresetPlateSlot)
|
||||
{
|
||||
// Found a plate, exit
|
||||
const plateItem = this.itemHelper.getItem(defaultPresetPlateSlot._tpl);
|
||||
platesOfDesiredLevel = [plateItem[1]];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Everything failed, no default plate or no default preset armor plate
|
||||
result.result = Result.NO_DEFAULT_FILTER;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// No plate found after filtering AND no default plate
|
||||
|
||||
// Last attempt, get default preset and see if it has a plate default
|
||||
const defaultPresetPlateSlot = this.getDefaultPresetArmorSlot(armorItem._id, modSlot);
|
||||
if (defaultPresetPlateSlot) {
|
||||
// Found a plate, exit
|
||||
const plateItem = this.itemHelper.getItem(defaultPresetPlateSlot._tpl);
|
||||
platesOfDesiredLevel = [plateItem[1]];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Everything failed, no default plate or no default preset armor plate
|
||||
result.result = Result.NO_DEFAULT_FILTER;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Only return the items ids
|
||||
result.result = Result.SUCCESS;
|
||||
result.plateModTpls = platesOfDesiredLevel.map((item) => item._id);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default plate an armor has in its db item
|
||||
@@ -457,7 +489,7 @@ public class BotEquipmentModGenerator(
|
||||
}
|
||||
|
||||
if (!IsModValidForSlot(modToAdd, modsParentSlot, modSlot, request.ParentTemplate, request.BotData.Role)
|
||||
)
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -608,7 +640,6 @@ public class BotEquipmentModGenerator(
|
||||
request.ModPool[modToAddTemplate.Value.Id] = modFromService;
|
||||
containsModInPool = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (containsModInPool)
|
||||
@@ -1033,10 +1064,13 @@ public class BotEquipmentModGenerator(
|
||||
var weaponTpl = modSpawnRequest.Weapon[0].Template;
|
||||
modSpawnRequest.RandomisationSettings.MinimumMagazineSize.TryGetValue(weaponTpl, out var minMagSizeFromSettings);
|
||||
var minMagazineSize = minMagSizeFromSettings;
|
||||
var desiredMagazineTpls = modPool.Where((magTpl) => {
|
||||
var magazineDb = _itemHelper.GetItem(magTpl).Value;
|
||||
return magazineDb.Properties is not null && magazineDb.Properties.Cartridges.FirstOrDefault().MaxCount >= minMagazineSize;
|
||||
});
|
||||
var desiredMagazineTpls = modPool.Where(
|
||||
(magTpl) =>
|
||||
{
|
||||
var magazineDb = _itemHelper.GetItem(magTpl).Value;
|
||||
return magazineDb.Properties is not null && magazineDb.Properties.Cartridges.FirstOrDefault().MaxCount >= minMagazineSize;
|
||||
}
|
||||
);
|
||||
|
||||
if (!desiredMagazineTpls.Any())
|
||||
{
|
||||
@@ -1467,7 +1501,8 @@ public class BotEquipmentModGenerator(
|
||||
/// <param name="modTemplate">db object for modItem we get compatible mods from</param>
|
||||
/// <param name="modPool">Pool of mods we are adding to</param>
|
||||
/// <param name="botEquipBlacklist">A blacklist of items that cannot be picked</param>
|
||||
public void AddCompatibleModsForProvidedMod(string desiredSlotName, TemplateItem modTemplate, Dictionary<string, Dictionary<string, HashSet<string>>> modPool,
|
||||
public void AddCompatibleModsForProvidedMod(string desiredSlotName, TemplateItem modTemplate,
|
||||
Dictionary<string, Dictionary<string, HashSet<string>>> modPool,
|
||||
EquipmentFilterDetails botEquipBlacklist)
|
||||
{
|
||||
var desiredSlotObject = modTemplate.Properties.Slots?.FirstOrDefault((slot) => slot.Name.Contains(desiredSlotName));
|
||||
@@ -1670,7 +1705,9 @@ public class BotEquipmentModGenerator(
|
||||
var whitelistedSightTypes = botWeaponSightWhitelist[weaponDetails.Value.Parent];
|
||||
if (whitelistedSightTypes is null)
|
||||
{
|
||||
_logger.Debug($"Unable to find whitelist for weapon type: {weaponDetails.Value.Parent} {weaponDetails.Value.Name}, skipping sight filtering");
|
||||
_logger.Debug(
|
||||
$"Unable to find whitelist for weapon type: {weaponDetails.Value.Parent} {weaponDetails.Value.Name}, skipping sight filtering"
|
||||
);
|
||||
|
||||
return scopes;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user