Partially implemented BotLootGenerator
This commit is contained in:
@@ -435,8 +435,8 @@ public class BotGenerator
|
||||
{
|
||||
// Adjust pocket loot weights to allow for 5 or 6 items
|
||||
var pocketWeights = botJsonTemplate.BotGeneration.Items["pocketLoot"].Weights;
|
||||
pocketWeights["5"] = 1;
|
||||
pocketWeights["6"] = 1;
|
||||
pocketWeights[5] = 1;
|
||||
pocketWeights[6] = 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,19 +1,74 @@
|
||||
using Core.Annotations;
|
||||
using Core.Annotations;
|
||||
using Core.Models.Eft.Common.Tables;
|
||||
using Core.Models.Enums;
|
||||
using Core.Models.Spt.Bots;
|
||||
using Core.Models.Spt.Config;
|
||||
using Core.Utils;
|
||||
using Core.Helpers;
|
||||
using Core.Services;
|
||||
using Core.Servers;
|
||||
using Core.Utils.Cloners;
|
||||
using ILogger = Core.Models.Utils.ILogger;
|
||||
|
||||
namespace Core.Generators;
|
||||
|
||||
[Injectable]
|
||||
public class BotLootGenerator
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly HashUtil _hashUtil;
|
||||
private readonly RandomUtil _randomUtil;
|
||||
private readonly ItemHelper _itemHelper;
|
||||
private readonly InventoryHelper _inventoryHelper;
|
||||
private readonly DatabaseService _databaseService;
|
||||
private readonly HandbookHelper _handbookHelper;
|
||||
private readonly BotGeneratorHelper _botGeneratorHelper;
|
||||
private readonly BotWeaponGenerator _botWeaponGenerator;
|
||||
private readonly WeightedRandomHelper _weightedRandomHelper;
|
||||
private readonly BotHelper _botHelper;
|
||||
private readonly BotLootCacheService _botLootCacheService;
|
||||
private readonly LocalisationService _localisationService;
|
||||
private readonly ConfigServer _configServer;
|
||||
private readonly ICloner _cloner;
|
||||
|
||||
private BotConfig _botConfig;
|
||||
private PmcConfig _pmcConfig;
|
||||
|
||||
public BotLootGenerator()
|
||||
public BotLootGenerator(
|
||||
ILogger logger,
|
||||
HashUtil hashUtil,
|
||||
RandomUtil randomUtil,
|
||||
ItemHelper itemHelper,
|
||||
InventoryHelper inventoryHelper,
|
||||
DatabaseService databaseService,
|
||||
HandbookHelper handbookHelper,
|
||||
BotGeneratorHelper botGeneratorHelper,
|
||||
BotWeaponGenerator botWeaponGenerator,
|
||||
WeightedRandomHelper weightedRandomHelper,
|
||||
BotHelper botHelper,
|
||||
BotLootCacheService botLootCacheService,
|
||||
LocalisationService localisationService,
|
||||
ConfigServer configServer,
|
||||
ICloner cloner)
|
||||
{
|
||||
_logger = logger;
|
||||
_hashUtil = hashUtil;
|
||||
_randomUtil = randomUtil;
|
||||
_itemHelper = itemHelper;
|
||||
_inventoryHelper = inventoryHelper;
|
||||
_databaseService = databaseService;
|
||||
_handbookHelper = handbookHelper;
|
||||
_botGeneratorHelper = botGeneratorHelper;
|
||||
_botWeaponGenerator = botWeaponGenerator;
|
||||
_weightedRandomHelper = weightedRandomHelper;
|
||||
_botHelper = botHelper;
|
||||
_botLootCacheService = botLootCacheService;
|
||||
_localisationService = localisationService;
|
||||
_configServer = configServer;
|
||||
_cloner = cloner;
|
||||
|
||||
_botConfig = _configServer.GetConfig<BotConfig>();
|
||||
_pmcConfig = _configServer.GetConfig<PmcConfig>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -38,7 +93,264 @@ public class BotLootGenerator
|
||||
/// <param name="botLevel">Level of bot</param>
|
||||
public void GenerateLoot(string sessionId, BotType botJsonTemplate, bool isPmc, string botRole, BotBaseInventory botInventory, int botLevel)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
// Limits on item types to be added as loot
|
||||
var itemCounts = botJsonTemplate.BotGeneration.Items;
|
||||
|
||||
if (
|
||||
itemCounts["backpackLoot"].Weights is null ||
|
||||
itemCounts["pocketLoot"].Weights is null ||
|
||||
itemCounts["vestLoot"].Weights is null ||
|
||||
itemCounts["specialItems"].Weights is null ||
|
||||
itemCounts["healing"].Weights is null ||
|
||||
itemCounts["drugs"].Weights is null ||
|
||||
itemCounts["food"].Weights is null ||
|
||||
itemCounts["drink"].Weights is null ||
|
||||
itemCounts["currency"].Weights is null ||
|
||||
itemCounts["stims"].Weights is null ||
|
||||
itemCounts["grenades"].Weights is null
|
||||
)
|
||||
{
|
||||
_logger.Warning(_localisationService.GetText("bot-unable_to_generate_bot_loot", botRole));
|
||||
return;
|
||||
}
|
||||
var backpackLootCount = _weightedRandomHelper.GetWeightedValue(itemCounts["backpackLoot"].Weights);
|
||||
var pocketLootCount = _weightedRandomHelper.GetWeightedValue(itemCounts["pocketLoot"].Weights);
|
||||
var vestLootCount = _weightedRandomHelper.GetWeightedValue(itemCounts["vestLoot"].Weights);
|
||||
var specialLootItemCount = _weightedRandomHelper.GetWeightedValue(itemCounts["specialItems"].Weights);
|
||||
var healingItemCount = _weightedRandomHelper.GetWeightedValue(itemCounts["healing"].Weights);
|
||||
var drugItemCount = _weightedRandomHelper.GetWeightedValue(itemCounts["drugs"].Weights);
|
||||
|
||||
var foodItemCount = _weightedRandomHelper.GetWeightedValue(itemCounts["food"].Weights);
|
||||
var drinkItemCount = _weightedRandomHelper.GetWeightedValue(itemCounts["drink"].Weights);
|
||||
|
||||
var currencyItemCount = _weightedRandomHelper.GetWeightedValue(itemCounts["currency"].Weights);
|
||||
|
||||
var stimItemCount = _weightedRandomHelper.GetWeightedValue(itemCounts["stims"].Weights);
|
||||
var grenadeCount = _weightedRandomHelper.GetWeightedValue(itemCounts["grenades"].Weights);
|
||||
|
||||
// If bot has been flagged as not having loot, set below counts to 0
|
||||
if (_botConfig.DisableLootOnBotTypes.Contains(botRole.ToLower()))
|
||||
{
|
||||
backpackLootCount = 0;
|
||||
pocketLootCount = 0;
|
||||
vestLootCount = 0;
|
||||
currencyItemCount = 0;
|
||||
}
|
||||
|
||||
// Forced pmc healing loot into secure container
|
||||
if (isPmc && _pmcConfig.ForceHealingItemsIntoSecure)
|
||||
{
|
||||
AddForcedMedicalItemsToPmcSecure(botInventory, botRole);
|
||||
}
|
||||
|
||||
var botItemLimits = GetItemSpawnLimitsForBot(botRole);
|
||||
|
||||
var containersBotHasAvailable = GetAvailableContainersBotCanStoreItemsIn(botInventory);
|
||||
|
||||
// This set is passed as a reference to fill up the containers that are already full, this alleviates
|
||||
// generation of the bots by avoiding checking the slots of containers we already know are full
|
||||
var containersIdFull = new List<string>();
|
||||
|
||||
// Special items
|
||||
AddLootFromPool(
|
||||
_botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.Special, botJsonTemplate),
|
||||
containersBotHasAvailable,
|
||||
specialLootItemCount,
|
||||
botInventory,
|
||||
botRole,
|
||||
botItemLimits,
|
||||
containersIdFull);
|
||||
|
||||
// Healing items / Meds
|
||||
AddLootFromPool(
|
||||
_botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.HealingItems, botJsonTemplate),
|
||||
containersBotHasAvailable,
|
||||
healingItemCount,
|
||||
botInventory,
|
||||
botRole,
|
||||
null,
|
||||
containersIdFull,
|
||||
0,
|
||||
isPmc);
|
||||
|
||||
// Drugs
|
||||
AddLootFromPool(
|
||||
_botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.DrugItems, botJsonTemplate),
|
||||
containersBotHasAvailable,
|
||||
drugItemCount,
|
||||
botInventory,
|
||||
botRole,
|
||||
null,
|
||||
containersIdFull,
|
||||
0,
|
||||
isPmc);
|
||||
|
||||
// Food
|
||||
AddLootFromPool(
|
||||
_botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.FoodItems, botJsonTemplate),
|
||||
containersBotHasAvailable,
|
||||
foodItemCount,
|
||||
botInventory,
|
||||
botRole,
|
||||
null,
|
||||
containersIdFull,
|
||||
0,
|
||||
isPmc);
|
||||
|
||||
// Drink
|
||||
AddLootFromPool(
|
||||
_botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.DrinkItems, botJsonTemplate),
|
||||
containersBotHasAvailable,
|
||||
drinkItemCount,
|
||||
botInventory,
|
||||
botRole,
|
||||
null,
|
||||
containersIdFull,
|
||||
0,
|
||||
isPmc);
|
||||
|
||||
// Currency
|
||||
AddLootFromPool(
|
||||
_botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.CurrencyItems, botJsonTemplate),
|
||||
containersBotHasAvailable,
|
||||
currencyItemCount,
|
||||
botInventory,
|
||||
botRole,
|
||||
null,
|
||||
containersIdFull,
|
||||
0,
|
||||
isPmc);
|
||||
|
||||
// Stims
|
||||
AddLootFromPool(
|
||||
_botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.StimItems, botJsonTemplate),
|
||||
containersBotHasAvailable,
|
||||
stimItemCount,
|
||||
botInventory,
|
||||
botRole,
|
||||
botItemLimits,
|
||||
containersIdFull,
|
||||
0,
|
||||
isPmc);
|
||||
|
||||
// Grenades
|
||||
AddLootFromPool(
|
||||
_botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.GrenadeItems, botJsonTemplate),
|
||||
[EquipmentSlots.Pockets, EquipmentSlots.TacticalVest], // Can't use containersBotHasEquipped as we don't want grenades added to backpack
|
||||
grenadeCount,
|
||||
botInventory,
|
||||
botRole,
|
||||
null,
|
||||
containersIdFull,
|
||||
0,
|
||||
isPmc);
|
||||
|
||||
var itemPriceLimits = GetSingleItemLootPriceLimits(botLevel, isPmc);
|
||||
|
||||
// Backpack - generate loot if they have one
|
||||
if (containersBotHasAvailable.Contains(EquipmentSlots.Backpack))
|
||||
{
|
||||
// Add randomly generated weapon to PMC backpacks
|
||||
if (isPmc && _randomUtil.GetChance100(_pmcConfig.LooseWeaponInBackpackChancePercent))
|
||||
{
|
||||
AddLooseWeaponsToInventorySlot(
|
||||
sessionId,
|
||||
botInventory,
|
||||
EquipmentSlots.Backpack,
|
||||
botJsonTemplate.BotInventory,
|
||||
botJsonTemplate.BotChances.WeaponModsChances,
|
||||
botRole,
|
||||
isPmc,
|
||||
botLevel,
|
||||
containersIdFull);
|
||||
}
|
||||
|
||||
var backpackLootRoubleTotal = GetBackpackRoubleTotalByLevel(botLevel, isPmc);
|
||||
AddLootFromPool(
|
||||
_botLootCacheService.GetLootFromCache(
|
||||
botRole,
|
||||
isPmc,
|
||||
LootCacheType.Backpack,
|
||||
botJsonTemplate,
|
||||
itemPriceLimits?.Backpack),
|
||||
[EquipmentSlots.Backpack],
|
||||
backpackLootCount,
|
||||
botInventory,
|
||||
botRole,
|
||||
botItemLimits,
|
||||
containersIdFull,
|
||||
backpackLootRoubleTotal,
|
||||
isPmc);
|
||||
}
|
||||
|
||||
// TacticalVest - generate loot if they have one
|
||||
if (containersBotHasAvailable.Contains(EquipmentSlots.TacticalVest))
|
||||
{
|
||||
// Vest
|
||||
AddLootFromPool(
|
||||
_botLootCacheService.GetLootFromCache(
|
||||
botRole,
|
||||
isPmc,
|
||||
LootCacheType.Vest,
|
||||
botJsonTemplate,
|
||||
itemPriceLimits?.Vest),
|
||||
[EquipmentSlots.TacticalVest],
|
||||
vestLootCount,
|
||||
botInventory,
|
||||
botRole,
|
||||
botItemLimits,
|
||||
containersIdFull,
|
||||
_pmcConfig.MaxVestLootTotalRub,
|
||||
isPmc);
|
||||
}
|
||||
|
||||
// Pockets
|
||||
AddLootFromPool(
|
||||
_botLootCacheService.GetLootFromCache(
|
||||
botRole,
|
||||
isPmc,
|
||||
LootCacheType.Pocket,
|
||||
botJsonTemplate,
|
||||
itemPriceLimits?.Pocket),
|
||||
[EquipmentSlots.Pockets],
|
||||
pocketLootCount,
|
||||
botInventory,
|
||||
botRole,
|
||||
botItemLimits,
|
||||
containersIdFull,
|
||||
_pmcConfig.MaxPocketLootTotalRub,
|
||||
isPmc);
|
||||
|
||||
// Secure
|
||||
|
||||
// only add if not a pmc or is pmc and flag is true
|
||||
if (!isPmc || (isPmc && _pmcConfig.AddSecureContainerLootFromBotConfig))
|
||||
{
|
||||
AddLootFromPool(
|
||||
_botLootCacheService.GetLootFromCache(botRole, isPmc, LootCacheType.Secure, botJsonTemplate),
|
||||
[EquipmentSlots.SecuredContainer],
|
||||
50,
|
||||
botInventory,
|
||||
botRole,
|
||||
null,
|
||||
containersIdFull,
|
||||
- 1,
|
||||
isPmc);
|
||||
}
|
||||
}
|
||||
|
||||
private MinMaxLootItemValue? GetSingleItemLootPriceLimits(int botLevel, bool isPmc)
|
||||
{
|
||||
// TODO - extend to other bot types
|
||||
if (isPmc)
|
||||
{
|
||||
var matchingValue = _pmcConfig.LootItemLimitsRub.FirstOrDefault(
|
||||
(minMaxValue) => botLevel >= minMaxValue.Min && botLevel <= minMaxValue.Max);
|
||||
|
||||
return matchingValue;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -87,9 +399,16 @@ public class BotLootGenerator
|
||||
/// <param name="totalValueLimitRub">Total value of loot allowed in roubles</param>
|
||||
/// <param name="isPmc">Is bot being generated for a pmc</param>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public void AddLootFromPool(Dictionary<string, int> pool, List<string> equipmentSlots, int totalItemCount,
|
||||
public void AddLootFromPool(
|
||||
Dictionary<string, int> pool,
|
||||
List<EquipmentSlots> equipmentSlots,
|
||||
int totalItemCount,
|
||||
BotBaseInventory inventoryToAddItemsTo, // TODO: type for containersIdFull was Set<string>
|
||||
string botRole, ItemSpawnLimitSettings? itemSpawnLimits, List<string> containersIdFull, int totalValueLimitRub = 0, bool isPmc = false)
|
||||
string botRole,
|
||||
ItemSpawnLimitSettings itemSpawnLimits,
|
||||
List<string> containersIdFull,
|
||||
int totalValueLimitRub = 0,
|
||||
bool isPmc = false)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -129,9 +448,15 @@ public class BotLootGenerator
|
||||
/// <param name="isPmc">are we generating for a pmc</param>
|
||||
/// <param name="botLevel"></param>
|
||||
/// <param name="containersIdFull"></param>
|
||||
public void AddLooseWeaponsToInventorySlot(string sessionId, BotBaseInventory botInventory, string equipmentSlot,
|
||||
BotBaseInventory templateInventory, // TODO: type for containersIdFull was Set<string>
|
||||
Dictionary<string, double> modsChances, string botRole, bool isPmc, int botLevel, List<string>? containersIdFull)
|
||||
public void AddLooseWeaponsToInventorySlot(string sessionId,
|
||||
BotBaseInventory botInventory,
|
||||
EquipmentSlots equipmentSlot,
|
||||
BotTypeInventory templateInventory,
|
||||
Dictionary<string, double> modsChances,
|
||||
string botRole,
|
||||
bool isPmc,
|
||||
int botLevel,
|
||||
List<string>? containersIdFull) // TODO: type for containersIdFull was Set<string>
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -303,7 +303,7 @@ public class GenerationData
|
||||
{
|
||||
/** key: number of items, value: weighting */
|
||||
[JsonPropertyName("weights")]
|
||||
public Dictionary<string, double>? Weights { get; set; }
|
||||
public Dictionary<int, int>? Weights { get; set; }
|
||||
|
||||
/** Array of item tpls */
|
||||
[JsonPropertyName("whitelist")]
|
||||
|
||||
@@ -44,7 +44,7 @@ public class BotLootCache
|
||||
public Dictionary<string, int>? GrenadeItems { get; set; }
|
||||
}
|
||||
|
||||
public static class LootCacheType
|
||||
public class LootCacheType
|
||||
{
|
||||
public const string Special = "Special";
|
||||
public const string Backpack = "Backpack";
|
||||
@@ -59,4 +59,4 @@ public static class LootCacheType
|
||||
public const string FoodItems = "FoodItems";
|
||||
public const string DrinkItems = "DrinkItems";
|
||||
public const string CurrencyItems = "CurrencyItems";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
using Core.Models.Common;
|
||||
using Core.Models.Eft.Common;
|
||||
using Core.Models.Enums;
|
||||
@@ -79,10 +79,10 @@ public class PmcConfig : BaseConfig
|
||||
public List<MinMaxLootValue> MaxBackpackLootTotalRub { get; set; }
|
||||
|
||||
[JsonPropertyName("maxPocketLootTotalRub")]
|
||||
public double MaxPocketLootTotalRub { get; set; }
|
||||
public int MaxPocketLootTotalRub { get; set; }
|
||||
|
||||
[JsonPropertyName("maxVestLootTotalRub")]
|
||||
public double MaxVestLootTotalRub { get; set; }
|
||||
public int MaxVestLootTotalRub { get; set; }
|
||||
|
||||
/** Percentage chance a bot from a wave is converted into a PMC, first key = map, second key = bot wildspawn type (assault/exusec), value: min+max chance to be converted */
|
||||
[JsonPropertyName("convertIntoPmcChance")]
|
||||
@@ -117,7 +117,7 @@ public class PmcConfig : BaseConfig
|
||||
public int? AddPrefixToSameNamePMCAsPlayerChance { get; set; }
|
||||
|
||||
[JsonPropertyName("lootItemLimitsRub")]
|
||||
public List<MinMaxLootValue>? LootItemLimitsRub { get; set; }
|
||||
public List<MinMaxLootItemValue>? LootItemLimitsRub { get; set; }
|
||||
}
|
||||
|
||||
public class HostilitySettings
|
||||
@@ -171,13 +171,16 @@ public class MinMaxLootValue : MinMax
|
||||
{
|
||||
[JsonPropertyName("value")]
|
||||
public double Value { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class MinMaxLootItemValue : MinMax
|
||||
{
|
||||
[JsonPropertyName("backpack")]
|
||||
public MinMax Backpack { get; set; }
|
||||
|
||||
|
||||
[JsonPropertyName("pocket")]
|
||||
public MinMax Pocket { get; set; }
|
||||
|
||||
|
||||
[JsonPropertyName("vest")]
|
||||
public MinMax Vest { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Core.Annotations;
|
||||
using Core.Generators;
|
||||
using Core.Helpers;
|
||||
using Core.Models.Common;
|
||||
using Core.Models.Eft.Common.Tables;
|
||||
using Core.Models.Spt.Bots;
|
||||
using Core.Utils.Cloners;
|
||||
@@ -54,7 +55,8 @@ public class BotLootCacheService
|
||||
string botRole,
|
||||
bool isPmc,
|
||||
string lootType,
|
||||
BotType botJsonTemplate)
|
||||
BotType botJsonTemplate,
|
||||
MinMax? itemPriceMinMax = null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user