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; using SptCommon.Annotations; 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 HashSet _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 !IsBotFollower(botRole) && _botConfig.Bosses.Any(x => string.Equals(x, botRole, StringComparison.CurrentCultureIgnoreCase)); } public bool IsBotFollower(string botRole) { return botRole?.StartsWith("follower", StringComparison.CurrentCultureIgnoreCase) ?? false; } public bool IsBotZombie(string botRole) { return botRole?.StartsWith("infected", StringComparison.CurrentCultureIgnoreCase) ?? 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); } } } /// /// is the provided role a PMC, case-agnostic /// /// Role to check /// True if role is PMC public bool BotRoleIsPmc(string botRole) { HashSet 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); } }