using Core.Annotations; using Core.Helpers; using Core.Models.Eft.Common.Tables; using Core.Models.Enums; using Core.Models.Spt.Bots; using Core.Models.Spt.Config; using Core.Servers; using Core.Services; using Core.Utils; using ILogger = Core.Models.Utils.ILogger; namespace Core.Generators; [Injectable] public class BotWeaponGenerator { private readonly ILogger _logger; private readonly HashUtil _hashUtil; private readonly RandomUtil _randomUtil; private readonly LocalisationService _localisationService; private readonly ItemHelper _itemHelper; private readonly BotGeneratorHelper _botGeneratorHelper; private readonly WeightedRandomHelper _weightedRandomHelper; private readonly RepairService _repairService; private readonly ConfigServer _configServer; private const string _modMagazineSlotId = "mod_magazine"; private BotConfig _botConfig; private PmcConfig _pmcConfig; private RepairConfig _repairConfig; public BotWeaponGenerator( ILogger logger, HashUtil hashUtil, RandomUtil randomUtil, LocalisationService localisationService, ItemHelper itemHelper, BotGeneratorHelper botGeneratorHelper, WeightedRandomHelper weightedRandomHelper, RepairService repairService, ConfigServer configServer) { _logger = logger; _hashUtil = hashUtil; _randomUtil = randomUtil; _localisationService = localisationService; _itemHelper = itemHelper; _botGeneratorHelper = botGeneratorHelper; _weightedRandomHelper = weightedRandomHelper; _repairService = repairService; _configServer = configServer; _botConfig = _configServer.GetConfig(); } /// /// Pick a random weapon based on weightings and generate a functional weapon /// /// Session identifier /// Primary/secondary/holster /// e.g. assault.json /// /// /// Role of bot, e.g. assault/followerBully /// Is weapon generated for a pmc /// /// GenerateWeaponResult object public GenerateWeaponResult GenerateRandomWeapon(string sessionId, EquipmentSlots equipmentSlot, BotTypeInventory botTemplateInventory, string weaponParentId, Dictionary modChances, string botRole, bool isPmc, int botLevel) { var weaponTpl = PickWeightedWeaponTemplateFromPool(equipmentSlot, botTemplateInventory); return GenerateWeaponByTpl( sessionId, weaponTpl, equipmentSlot, botTemplateInventory, weaponParentId, modChances, botRole, isPmc, botLevel); } /// /// Gets a random weighted weapon from a bot's pool of weapons. /// /// Primary/secondary/holster /// e.g. assault.json /// Weapon template public string PickWeightedWeaponTemplateFromPool(EquipmentSlots equipmentSlot, BotTypeInventory botTemplateInventory) { var weaponPool = botTemplateInventory.Equipment[equipmentSlot]; return _weightedRandomHelper.GetWeightedValue(weaponPool); } /// /// Generates a weapon based on the supplied weapon template. /// /// The session identifier. /// Weapon template to generate (use pickWeightedWeaponTplFromPool()). /// Slot to fit into, primary/secondary/holster. /// e.g. assault.json. /// Parent ID of the weapon being generated. /// Dictionary of item types and % chance weapon will have that mod. /// e.g. assault/exusec. /// Is weapon being generated for a PMC. /// The level of the bot. /// GenerateWeaponResult object. public GenerateWeaponResult? GenerateWeaponByTpl(string sessionId, string weaponTpl, EquipmentSlots slotName, BotTypeInventory botTemplateInventory, string weaponParentId, Dictionary modChances, string botRole, bool isPmc, int botLevel) { var modPool = botTemplateInventory.Mods; var weaponItemTemplate = _itemHelper.GetItem(weaponTpl).Value; if (weaponItemTemplate is null) { _logger.Error(_localisationService.GetText("bot-missing_item_template", weaponTpl)); _logger.Error($"WeaponSlot-> { slotName}"); return null; } // Find ammo to use when filling magazines/chamber if (botTemplateInventory.Ammo is not null) { _logger.Error(_localisationService.GetText("bot-no_ammo_found_in_bot_json", botRole)); _logger.Error(_localisationService.GetText("bot-generation_failed")); return null; } var ammoTpl = GetWeightedCompatibleAmmo(botTemplateInventory.Ammo, weaponItemTemplate); // Create with just base weapon item var weaponWithModsArray = ConstructWeaponBaseList( weaponTpl, weaponParentId, slotName, weaponItemTemplate, botRole); // Chance to add randomised weapon enhancement if (isPmc && _randomUtil.GetChance100(_pmcConfig.WeaponHasEnhancementChancePercent)) { // Add buff to weapon root _repairService.AddBuff(_repairConfig.RepairKit.Weapon, weaponWithModsArray[0]); } throw new NotImplementedException(); } /// /// Insert cartridge(s) into a weapon /// Handles all chambers - patron_in_weapon, patron_in_weapon_000 etc /// /// Weapon and mods /// Cartridge to add to weapon /// Name of slots to create or add ammo to protected void AddCartridgeToChamber(List weaponWithModsList, string ammoTemplate, List chamberSlotIdentifiers) { throw new NotImplementedException(); } /// /// Create a list with weapon base as the only element and /// add additional properties based on weapon type /// /// Weapon template to create item with /// Weapons parent id /// e.g. primary/secondary/holster /// Database template for weapon /// For durability values /// Base weapon item in a list protected List ConstructWeaponBaseList(string weaponTemplate, string weaponParentId, EquipmentSlots equipmentSlot, TemplateItem weaponItemTemplate, string botRole) { return [ new() { Id = _hashUtil.Generate(), Template = weaponTemplate, ParentId = weaponParentId, SlotId = equipmentSlot.ToString(), Upd = _botGeneratorHelper.GenerateExtraPropertiesForItem(weaponItemTemplate, botRole) } ]; } /// /// Get the mods necessary to kit out a weapon to its preset level /// /// Weapon to find preset for /// The slot the weapon will be placed in /// Value used for the parent id /// Item template /// Bot role /// List of weapon mods protected List GetPresetWeaponMods(string weaponTemplate, string equipmentSlot, string weaponParentId, TemplateItem itemTemplate, string botRole) { throw new NotImplementedException(); } /// /// Checks if all required slots are occupied on a weapon and all its mods. /// /// Weapon + mods /// Role of bot weapon is for /// True if valid protected bool IsWeaponValid(List weaponItemList, string botRole) { throw new NotImplementedException(); } /// /// Generates extra magazines or bullets (if magazine is internal) and adds them to TacticalVest and Pockets. /// Additionally, adds extra bullets to SecuredContainer /// /// Object with properties for generated weapon (weapon mods pool / weapon template / ammo tpl) /// Magazine weights for count to add to inventory /// Inventory to add magazines to /// The bot type we're generating extra mags for public void AddExtraMagazinesToInventory(GenerateWeaponResult generatedWeaponResult, GenerationData magWeights, BotBaseInventory inventory, string botRole) { throw new NotImplementedException(); } /// /// Add Grenades for UBGL to bot's vest and secure container /// /// Weapon list with mods /// Result of weapon generation /// Bot inventory to add grenades to protected void AddUbglGrenadesToBotInventory(List weaponMods, GenerateWeaponResult generatedWeaponResult, BotBaseInventory inventory) { throw new NotImplementedException(); } /// /// Add ammo to the secure container. /// /// How many stacks of ammo to add. /// Ammo type to add. /// Size of the ammo stack to add. /// Player inventory. protected void AddAmmoToSecureContainer(int stackCount, string ammoTemplate, int stackSize, BotBaseInventory inventory) { throw new NotImplementedException(); } /// /// Get a weapons magazine template from a weapon template. /// /// Mods from a weapon template. /// Weapon to get magazine template for. /// The bot type we are getting the magazine for. /// Magazine template string. protected string GetMagazineTemplateFromWeaponTemplate(List weaponMods, TemplateItem weaponTemplate, string botRole) { throw new NotImplementedException(); } /// /// Finds and returns a compatible ammo template based on the bots ammo weightings (x.json/inventory/equipment/ammo) /// /// Dictionary of all cartridges keyed by type e.g. Caliber556x45NATO /// Weapon details from database we want to pick ammo for /// Ammo template that works with the desired gun protected string GetWeightedCompatibleAmmo(Dictionary> cartridgePool, TemplateItem weaponTemplate) { throw new NotImplementedException(); } /// /// Get the cartridge ids from a weapon template that work with the weapon /// /// Weapon db template to get cartridges for /// List of cartridge tpls protected List GetCompatibleCartridgesFromWeaponTemplate(TemplateItem weaponTemplate) { throw new NotImplementedException(); } /// /// Get a weapons compatible cartridge caliber /// /// Weapon to look up caliber of /// Caliber as string protected string GetWeaponCaliber(TemplateItem weaponTemplate) { throw new NotImplementedException(); } /// /// Fill existing magazines to full, while replacing their contents with specified ammo /// /// Weapon with children /// Magazine item /// Cartridge to insert into magazine protected void FillExistingMagazines(List weaponMods, Item magazine, string cartridgeTemplate) { throw new NotImplementedException(); } /// /// Add desired ammo template as item to weapon modifications list, placed as child to UBGL. /// /// Weapon with children. /// UBGL item. /// Grenade ammo template. protected void FillUbgl(List weaponMods, Item ubglMod, string ubglAmmoTpl) { throw new NotImplementedException(); } /// /// Add cartridge item to weapon item list, if it already exists, update /// /// Weapon items list to amend /// Magazine item details we're adding cartridges to /// Cartridge to put into the magazine /// How many cartridges should go into the magazine /// Magazines db template protected void AddOrUpdateMagazinesChildWithAmmo(List weaponWithMods, Item magazine, string chosenAmmoTpl, TemplateItem magazineTemplate) { throw new NotImplementedException(); } /// /// Fill each Camora with a bullet /// /// Weapon mods to find and update camora mod(s) from /// Magazine id to find and add to /// Ammo template id to hydrate with protected void FillCamorasWithAmmo(List weaponMods, string magazineId, string ammoTpl) { throw new NotImplementedException(); } }