using Core.Annotations; using Core.Models.Common; using Core.Models.Eft.Common; using Core.Models.Eft.Common.Tables; using Core.Models.Enums; using Core.Models.Enums.RaidSettings; using Core.Models.Spt.Bots; using Core.Models.Spt.Config; using Core.Services; using Core.Utils.Cloners; using BodyPart = Core.Models.Eft.Common.Tables.BodyPart; using ILogger = Core.Models.Utils.ILogger; namespace Core.Generators; [Injectable] public class BotGenerator { private readonly ILogger _logger; private readonly DatabaseService _databaseService; private readonly ICloner _cloner; private BotConfig _botConfig; private PmcConfig _pmcConfig; public BotGenerator( ILogger logger, DatabaseService databaseService, ICloner cloner ) { _logger = logger; _databaseService = databaseService; _cloner = cloner; } /// /// Generate a player scav bot object /// /// Session id /// e.g. assault / pmcbot /// easy/normal/hard/impossible /// base bot template to use (e.g. assault/pmcbot) /// profile of player generating pscav /// BotBase public BotBase GeneratePlayerScav(string sessionId, string role, string difficulty, BotType botTemplate, PmcData profile) { var bot = GetCloneOfBotBase(); bot.Info.Settings.BotDifficulty = difficulty; bot.Info.Settings.Role = role; bot.Info.Side = "Savage"; var botGenDetails = new BotGenerationDetails{ IsPmc = false, Side = "Savage", Role = role, BotRelativeLevelDeltaMax = 0, BotRelativeLevelDeltaMin = 0, BotCountToGenerate = 1, BotDifficulty = difficulty, IsPlayerScav = true, }; bot = GenerateBot(sessionId, bot, botTemplate, botGenDetails); // Sets the name after scav name shown in parentheses bot.Info.MainProfileNickname = profile.Info.Nickname; return bot; } /// /// Create 1 bot of the type/side/difficulty defined in botGenerationDetails /// /// Session id /// details on how to generate bots /// constructed bot public BotBase PrepareAndGenerateBot(string sessionId, BotGenerationDetails botGenerationDetails) { throw new NotImplementedException(); } /// /// Get a clone of the default bot base object and adjust its role/side/difficulty values /// /// Role bot should have /// Side bot should have /// Difficult bot should have /// Cloned bot base public BotBase GetPreparedBotBase(string botRole, string botSide, string difficulty) { throw new NotImplementedException(); } /// /// Get a clone of the database\bots\base.json file /// /// BotBase object public BotBase GetCloneOfBotBase() { return _cloner.Clone(_databaseService.GetBots().Base); } /// /// Create a IBotBase object with equipment/loot/exp etc /// /// Session id /// Bots base file /// Bot template from db/bots/x.json /// details on how to generate the bot /// BotBase object public BotBase GenerateBot(string sessionId, BotBase bot, BotType botJsonTemplate, BotGenerationDetails botGenerationDetails) { _logger.Error("NOT IMPLEMENTED BotGenerator.GenerateBot"); return new BotBase(); } /// /// Should this bot have a name like "name (Pmc Name)" and be alterd by client patch to be hostile to player /// /// Role bot has /// True if name should be simulated pscav public bool ShouldSimulatePlayerScav(string botRole) { throw new NotImplementedException(); } /// /// Get exp for kill by bot difficulty /// /// Dict of difficulties and experience /// the killed bots difficulty /// Role of bot (optional, used for error logging) /// Experience for kill public int GetExperienceRewardForKillByDifficulty(Dictionary experience, string botDifficulty, string role) { throw new NotImplementedException(); } /// /// Get the standing value change when player kills a bot /// /// Dictionary of standing values keyed by bot difficulty /// Difficulty of bot to look up /// Role of bot (optional, used for error logging) /// Standing change value public int GetStandingChangeForKillByDifficulty(Dictionary standingForKill, string botDifficulty, string role) { throw new NotImplementedException(); } /// /// Get the agressor bonus value when player kills a bot /// /// Dictionary of standing values keyed by bot difficulty /// Difficulty of bot to look up /// Role of bot (optional, used for error logging) /// Standing change value public int GetAgressorBonusByDifficulty(Dictionary aggressorBonus, string botDifficulty, string role) { throw new NotImplementedException(); } /// /// Set weighting of flagged equipment to 0 /// /// Bot data to adjust /// Generation details of bot public void FilterBlacklistedGear(BotType botJsonTemplate, BotGenerationDetails botGenerationDetails) { throw new NotImplementedException(); } /// /// TODO: Complete Summary /// /// Bot data to adjust public void AddAdditionalPocketLootWeightsForUnheardBot(BotType botJsonTemplate) { throw new NotImplementedException(); } /// /// Remove items from item.json/lootableItemBlacklist from bots inventory /// /// Bot to filter public void RemoveBlacklistedLootFromBotTemplate(BotTypeInventory botInventory) { throw new NotImplementedException(); } /// /// Choose various appearance settings for a bot using weights: head/body/feet/hands /// /// Bot to adjust /// Appearance settings to choose from /// Generation details public void SetBotAppearance(BotBase bot, Appearance appearance, BotGenerationDetails botGenerationDetails) { throw new NotImplementedException(); } /// /// Log the number of PMCs generated to the debug console /// /// Generated bot array, ready to send to client public void LogPmcGeneratedCount(List output) { throw new NotImplementedException(); } /// /// Converts health object to the required format /// /// health object from bot json /// Is a pscav bot being generated /// Health object public Health GenerateHealth(Health healthObj, bool playerScav = false) { throw new NotImplementedException(); } /// /// Sum up body parts max hp values, return the bodypart collection with lowest value /// /// Body parts to sum up /// Lowest hp collection public BodyPart? GetLowestHpBody(List bodies) // TODO: there are two types of body parts { throw new NotImplementedException(); } /// /// Get a bots skills with randomsied progress value between the min and max values /// /// Skills that should have their progress value randomised /// Skills public Skills GenerateSkills(BaseJsonSkills botSkills) { throw new NotImplementedException(); } /// /// Randomise the progress value of passed in skills based on the min/max value /// /// Skills to randomise /// Are the skills 'common' skills /// Skills with randomised progress values as an array public List GetSkillsWithRandomisedProgressValue(Dictionary skills, bool isCommonSkills) { throw new NotImplementedException(); } /// /// Generate an id+aid for a bot and apply /// /// bot to update /// updated IBotBase object // TODO: Node server claims this in summary but is void public void AddIdsToBot(BotBase bot) { throw new NotImplementedException(); } /// /// Update a profiles profile.Inventory.equipment value with a freshly generated one. /// Update all inventory items that make use of this value too. /// /// Profile to update public void GenerateInventoryId(BotBase profile) { throw new NotImplementedException(); } /// /// Randomise a bots game version and account category. /// Chooses from all the game versions (standard, eod etc). /// Chooses account type (default, Sherpa, etc). /// /// bot info object to update /// Chosen game version public string SetRandomisedGameVersionAndCategory(Info botInfo) // TODO: there are two types of Info { throw new NotImplementedException(); } /// /// Add a side-specific (usec/bear) dogtag item to a bots inventory /// /// bot to add dogtag to /// Bot with dogtag added // TODO: Node server claims this in summary but is void public void AddDogtagToBot(BotBase bot) { throw new NotImplementedException(); } /// /// Get a dogtag tpl that matches the bots game version and side /// /// Usec/Bear /// edge_of_darkness / standard /// item tpl public string GetDogtagTplByGameVersionAndSide(string side, string gameVersion) { throw new NotImplementedException(); } /// /// Adjust a PMCs pocket tpl to UHD if necessary, otherwise do nothing /// /// Pmc object to adjust public void SetPmcPocketsByGameVersion(BotBase bot) { throw new NotImplementedException(); } }