using SptCommon.Annotations; using Core.Models.Common; using Core.Models.Eft.Common.Tables; using Core.Models.Spt.Config; using Core.Models.Utils; using Core.Servers; using Core.Services; using Core.Utils; namespace Core.Helpers; [Injectable] public class BotHelper( ISptLogger _logger, DatabaseService _databaseService, RandomUtil _randomUtil, ConfigServer _configServer ) { protected BotConfig _botConfig = _configServer.GetConfig(); protected PmcConfig _pmcConfig = _configServer.GetConfig(); protected List _pmcNames = ["usec", "bear", "pmc", "pmcbear", "pmcusec"]; /// /// Get a template object for the specified botRole from bots.types db /// /// botRole to get template for /// BotType object public BotType? GetBotTemplate(string role) { if (!_databaseService.GetBots().Types.TryGetValue(role?.ToLower(), out var bot)) { _logger.Error($"Unable to get bot of type: {role} from DB"); return null; } return bot; } /// /// Is the passed in bot role a PMC (usec/bear/pmc) /// /// bot role to check /// true if is pmc public bool IsBotPmc(string? botRole) { return _pmcNames.Contains(botRole?.ToLower()); } public bool IsBotBoss(string botRole) { return _botConfig.Bosses.Any(x => string.Equals(x, botRole, StringComparison.CurrentCultureIgnoreCase)); } public bool IsBotFollower(string botRole) { return botRole?.ToLower().StartsWith("follower") ?? false; } public bool IsBotZombie(string botRole) { return botRole?.ToLower().StartsWith("infected") ?? false; } /// /// Add a bot to the FRIENDLY_BOT_TYPES list /// /// bot settings to alter /// bot type to add to friendly list public void AddBotToFriendlyList(DifficultyCategories difficultySettings, string typeToAdd) { var friendlyBotTypesKey = "FRIENDLY_BOT_TYPES"; // Null guard if (difficultySettings.Mind[friendlyBotTypesKey] is null) difficultySettings.Mind[friendlyBotTypesKey] = new List(); ((List)difficultySettings.Mind[friendlyBotTypesKey]).Add(typeToAdd); } /// /// Add a bot to the REVENGE_BOT_TYPES list /// /// bot settings to alter /// bot type to add to revenge list public void AddBotToRevengeList(DifficultyCategories difficultySettings, string[] typesToAdd) { var revengePropKey = "REVENGE_BOT_TYPES"; // Nothing to add if (typesToAdd is null) return; // Null guard if (difficultySettings.Mind[revengePropKey] is null) difficultySettings.Mind[revengePropKey] = new List(); var revengeArray = (List)difficultySettings.Mind[revengePropKey]; foreach (var botTypeToAdd in typesToAdd) if (!revengeArray.Contains(botTypeToAdd)) revengeArray.Add(botTypeToAdd); } public bool RollChanceToBePmc(MinMax botConvertMinMax) { return _randomUtil.GetChance100(_randomUtil.GetInt((int)botConvertMinMax.Min, (int)botConvertMinMax.Max)); } protected Dictionary GetPmcConversionValuesForLocation(string location) { var result = _pmcConfig.ConvertIntoPmcChance[location.ToLower()]; if (result is null) _pmcConfig.ConvertIntoPmcChance = new Dictionary>(); return result; } /// /// is the provided role a PMC, case-agnostic /// /// Role to check /// True if role is PMC public bool BotRoleIsPmc(string botRole) { List ListToCheck = [_pmcConfig.UsecType.ToLower(), _pmcConfig.BearType.ToLower()]; return ListToCheck.Contains( botRole.ToLower() ); } /// /// Get randomization settings for bot from config/bot.json /// /// level of bot /// bot equipment json /// RandomisationDetails public RandomisationDetails GetBotRandomizationDetails(int botLevel, EquipmentFilters botEquipConfig) { // No randomisation details found, skip if (botEquipConfig is null || botEquipConfig.Randomisation is null) return null; return botEquipConfig.Randomisation.FirstOrDefault( (randDetails) => botLevel >= randDetails.LevelRange.Min && botLevel <= randDetails.LevelRange.Max ); } /// /// Choose between pmcBEAR and pmcUSEC at random based on the % defined in pmcConfig.isUsec /// /// pmc role public string GetRandomizedPmcRole() { return _randomUtil.GetChance100(_pmcConfig.IsUsec) ? _pmcConfig.UsecType : _pmcConfig.BearType; } /// /// Get the corresponding side when pmcBEAR or pmcUSEC is passed in /// /// role to get side for /// side (usec/bear) public string GetPmcSideByRole(string botRole) { if (_pmcConfig.BearType.ToLower() == botRole.ToLower()) return "Bear"; if (_pmcConfig.UsecType.ToLower() == botRole.ToLower()) return "Usec"; return GetRandomizedPmcSide(); } /// /// Get a randomized PMC side based on bot config value 'isUsec' /// /// pmc side as string protected string GetRandomizedPmcSide() { return _randomUtil.GetChance100(_pmcConfig.IsUsec) ? "Usec" : "Bear"; } /// /// Get a name from a PMC that fits the desired length /// /// Max length of name, inclusive /// OPTIONAL - what side PMC to get name from (usec/bear) /// name of PMC public string GetPmcNicknameOfMaxLength(int maxLength, string side = null) { var randomType = side is not null ? side : _randomUtil.GetInt(0, 1) == 0 ? "usec" : "bear"; var allNames = _databaseService.GetBots().Types[randomType.ToLower()].FirstNames; var filteredNames = allNames.Where((name) => name.Length <= maxLength); if (filteredNames.Count() == 0) { _logger.Warning( $"Unable to filter: {randomType} PMC names to only those under: {maxLength}, none found that match that criteria, selecting from entire name pool instead`,\n" ); return _randomUtil.GetStringCollectionValue(allNames); } return _randomUtil.GetStringCollectionValue(filteredNames); } }