Move generators to primary ctor
This commit is contained in:
@@ -15,75 +15,29 @@ using Core.Utils.Cloners;
|
||||
namespace Core.Generators;
|
||||
|
||||
[Injectable]
|
||||
public class BotEquipmentModGenerator
|
||||
public class BotEquipmentModGenerator(
|
||||
ISptLogger<BotEquipmentModGenerator> _logger,
|
||||
HashUtil _hashUtil,
|
||||
RandomUtil _randomUtil,
|
||||
ProbabilityHelper _probabilityHelper,
|
||||
DatabaseService _databaseService,
|
||||
ItemHelper _itemHelper,
|
||||
BotEquipmentFilterService _botEquipmentFilterService,
|
||||
ItemFilterService _itemFilterService,
|
||||
ProfileHelper _profileHelper,
|
||||
BotWeaponModLimitService _botWeaponModLimitService,
|
||||
BotHelper _botHelper,
|
||||
BotGeneratorHelper _botGeneratorHelper,
|
||||
BotWeaponGeneratorHelper _botWeaponGeneratorHelper,
|
||||
WeightedRandomHelper _weightedRandomHelper,
|
||||
PresetHelper _presetHelper,
|
||||
LocalisationService _localisationService,
|
||||
BotEquipmentModPoolService _botEquipmentModPoolService,
|
||||
ConfigServer _configServer,
|
||||
ICloner _cloner
|
||||
)
|
||||
{
|
||||
private readonly ISptLogger<BotEquipmentModGenerator> _logger;
|
||||
private readonly HashUtil _hashUtil;
|
||||
private readonly RandomUtil _randomUtil;
|
||||
private readonly ProbabilityHelper _probabilityHelper;
|
||||
private readonly DatabaseService _databaseService;
|
||||
private readonly ItemHelper _itemHelper;
|
||||
private readonly BotEquipmentFilterService _botEquipmentFilterService;
|
||||
private readonly ItemFilterService _itemFilterService;
|
||||
private readonly ProfileHelper _profileHelper;
|
||||
private readonly BotWeaponModLimitService _botWeaponModLimitService;
|
||||
private readonly BotHelper _botHelper;
|
||||
private readonly BotGeneratorHelper _botGeneratorHelper;
|
||||
private readonly BotWeaponGeneratorHelper _botWeaponGeneratorHelper;
|
||||
private readonly WeightedRandomHelper _weightedRandomHelper;
|
||||
private readonly PresetHelper _presetHelper;
|
||||
private readonly LocalisationService _localisationService;
|
||||
private readonly BotEquipmentModPoolService _botEquipmentModPoolService;
|
||||
private readonly ConfigServer _configServer;
|
||||
private readonly ICloner _cloner;
|
||||
|
||||
private BotConfig _botConfig;
|
||||
|
||||
public BotEquipmentModGenerator
|
||||
(
|
||||
ISptLogger<BotEquipmentModGenerator> logger,
|
||||
HashUtil hashUtil,
|
||||
RandomUtil randomUtil,
|
||||
ProbabilityHelper probabilityHelper,
|
||||
DatabaseService databaseService,
|
||||
ItemHelper itemHelper,
|
||||
BotEquipmentFilterService botEquipmentFilterService,
|
||||
ItemFilterService itemFilterService,
|
||||
ProfileHelper profileHelper,
|
||||
BotWeaponModLimitService botWeaponModLimitService,
|
||||
BotHelper botHelper,
|
||||
BotGeneratorHelper botGeneratorHelper,
|
||||
BotWeaponGeneratorHelper botWeaponGeneratorHelper,
|
||||
WeightedRandomHelper weightedRandomHelper,
|
||||
PresetHelper presetHelper,
|
||||
LocalisationService localisationService,
|
||||
BotEquipmentModPoolService botEquipmentModPoolService,
|
||||
ConfigServer configServer,
|
||||
ICloner cloner
|
||||
)
|
||||
{
|
||||
_logger = logger;
|
||||
_hashUtil = hashUtil;
|
||||
_randomUtil = randomUtil;
|
||||
_probabilityHelper = probabilityHelper;
|
||||
_databaseService = databaseService;
|
||||
_itemHelper = itemHelper;
|
||||
_botEquipmentFilterService = botEquipmentFilterService;
|
||||
_itemFilterService = itemFilterService;
|
||||
_profileHelper = profileHelper;
|
||||
_botWeaponModLimitService = botWeaponModLimitService;
|
||||
_botHelper = botHelper;
|
||||
_botGeneratorHelper = botGeneratorHelper;
|
||||
_botWeaponGeneratorHelper = botWeaponGeneratorHelper;
|
||||
_weightedRandomHelper = weightedRandomHelper;
|
||||
_presetHelper = presetHelper;
|
||||
_localisationService = localisationService;
|
||||
_botEquipmentModPoolService = botEquipmentModPoolService;
|
||||
_configServer = configServer;
|
||||
_cloner = cloner;
|
||||
|
||||
_botConfig = _configServer.GetConfig<BotConfig>();
|
||||
}
|
||||
protected BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
|
||||
|
||||
/// <summary>
|
||||
/// Check mods are compatible and add to array
|
||||
@@ -174,7 +128,9 @@ public class BotEquipmentModGenerator
|
||||
switch (plateSlotFilteringOutcome.Result)
|
||||
{
|
||||
case Result.UNKNOWN_FAILURE or Result.NO_DEFAULT_FILTER:
|
||||
_logger.Debug($"Plate slot: {modSlotName} selection for armor: {parentTemplate.Id} failed: {plateSlotFilteringOutcome.Result}, skipping");
|
||||
_logger.Debug(
|
||||
$"Plate slot: {modSlotName} selection for armor: {parentTemplate.Id} failed: {plateSlotFilteringOutcome.Result}, skipping"
|
||||
);
|
||||
|
||||
continue;
|
||||
case Result.LACKS_PLATE_WEIGHTS:
|
||||
@@ -275,7 +231,8 @@ public class BotEquipmentModGenerator
|
||||
* @param modSlot front/back
|
||||
* @returns Tpl of plate
|
||||
*/
|
||||
protected string GetDefaultPlateTpl(TemplateItem armorItem, string modSlot ) {
|
||||
protected string GetDefaultPlateTpl(TemplateItem armorItem, string modSlot)
|
||||
{
|
||||
var relatedItemDbModSlot = armorItem.Properties.Slots?.FirstOrDefault(slot => slot.Name.ToLower() == modSlot);
|
||||
|
||||
return relatedItemDbModSlot?.Props.Filters[0].Plate;
|
||||
@@ -287,20 +244,21 @@ public class BotEquipmentModGenerator
|
||||
* @param modSlot front/back
|
||||
* @returns Armor IItem
|
||||
*/
|
||||
protected Item GetDefaultPresetArmorSlot(string armorItemTpl, string modSlot) {
|
||||
protected Item GetDefaultPresetArmorSlot(string armorItemTpl, string modSlot)
|
||||
{
|
||||
var defaultPreset = _presetHelper.GetDefaultPreset(armorItemTpl);
|
||||
|
||||
return defaultPreset?.Items.FirstOrDefault((item) => item.SlotId?.ToLower() == modSlot);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Add mods to a weapon using the provided mod pool
|
||||
/// </summary>
|
||||
/// <param name="sessionId">Session id</param>
|
||||
/// <param name="request">Data used to generate the weapon</param>
|
||||
/// <returns>Weapon + mods array</returns>
|
||||
public List<Item> GenerateModsForWeapon(string sessionId, GenerateWeaponRequest request)
|
||||
/// <summary>
|
||||
/// Add mods to a weapon using the provided mod pool
|
||||
/// </summary>
|
||||
/// <param name="sessionId">Session id</param>
|
||||
/// <param name="request">Data used to generate the weapon</param>
|
||||
/// <returns>Weapon + mods array</returns>
|
||||
public List<Item> GenerateModsForWeapon(string sessionId, GenerateWeaponRequest request)
|
||||
{
|
||||
var pmcProfile = _profileHelper.GetPmcProfile(sessionId);
|
||||
|
||||
@@ -1399,14 +1357,16 @@ public List<Item> GenerateModsForWeapon(string sessionId, GenerateWeaponRequest
|
||||
var filteredMods = FilterModsByBlacklist(supportedSubMods, botEquipBlacklist, desiredSlotName);
|
||||
if (!filteredMods.Any())
|
||||
{
|
||||
_logger.Warning(_localisationService
|
||||
.GetText("bot-unable_to_filter_mods_all_blacklisted",
|
||||
new
|
||||
{
|
||||
slotName = desiredSlotObject.Name,
|
||||
itemName = modTemplate.Name,
|
||||
}
|
||||
)
|
||||
_logger.Warning(
|
||||
_localisationService
|
||||
.GetText(
|
||||
"bot-unable_to_filter_mods_all_blacklisted",
|
||||
new
|
||||
{
|
||||
slotName = desiredSlotObject.Name,
|
||||
itemName = modTemplate.Name,
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+90
-106
@@ -18,69 +18,28 @@ using BodyPart = Core.Models.Eft.Common.Tables.BodyPart;
|
||||
namespace Core.Generators;
|
||||
|
||||
[Injectable]
|
||||
public class BotGenerator
|
||||
public class BotGenerator(
|
||||
ISptLogger<BotGenerator> _logger,
|
||||
HashUtil _hashUtil,
|
||||
RandomUtil _randomUtil,
|
||||
TimeUtil _timeUtil,
|
||||
ProfileHelper _profileHelper,
|
||||
DatabaseService _databaseService,
|
||||
BotInventoryGenerator _botInventoryGenerator,
|
||||
BotLevelGenerator _botLevelGenerator,
|
||||
BotEquipmentFilterService _botEquipmentFilterService,
|
||||
WeightedRandomHelper _weightedRandomHelper,
|
||||
BotHelper _botHelper,
|
||||
BotGeneratorHelper _botGeneratorHelper,
|
||||
SeasonalEventService _seasonalEventService,
|
||||
ItemFilterService _itemFilterService,
|
||||
BotNameService _botNameService,
|
||||
ConfigServer _configServer,
|
||||
ICloner _cloner
|
||||
)
|
||||
{
|
||||
protected ISptLogger<BotGenerator> _logger;
|
||||
protected HashUtil _hashUtil;
|
||||
protected RandomUtil _randomUtil;
|
||||
protected TimeUtil _timeUtil;
|
||||
protected ProfileHelper _profileHelper;
|
||||
protected DatabaseService _databaseService;
|
||||
protected BotInventoryGenerator _botInventoryGenerator;
|
||||
protected BotLevelGenerator _botLevelGenerator;
|
||||
protected BotEquipmentFilterService _botEquipmentFilterService;
|
||||
protected WeightedRandomHelper _weightedRandomHelper;
|
||||
protected BotHelper _botHelper;
|
||||
protected BotGeneratorHelper _botGeneratorHelper;
|
||||
protected SeasonalEventService _seasonalEventService;
|
||||
protected ItemFilterService _itemFilterService;
|
||||
protected BotNameService _botNameService;
|
||||
protected ConfigServer _configServer;
|
||||
protected ICloner _cloner;
|
||||
private BotConfig _botConfig;
|
||||
private PmcConfig _pmcConfig;
|
||||
|
||||
public BotGenerator(
|
||||
ISptLogger<BotGenerator> logger,
|
||||
HashUtil hashUtil,
|
||||
RandomUtil randomUtil,
|
||||
TimeUtil timeUtil,
|
||||
ProfileHelper profileHelper,
|
||||
DatabaseService databaseService,
|
||||
BotInventoryGenerator botInventoryGenerator,
|
||||
BotLevelGenerator botLevelGenerator,
|
||||
BotEquipmentFilterService botEquipmentFilterService,
|
||||
WeightedRandomHelper weightedRandomHelper,
|
||||
BotHelper botHelper,
|
||||
BotGeneratorHelper botGeneratorHelper,
|
||||
SeasonalEventService seasonalEventService,
|
||||
ItemFilterService itemFilterService,
|
||||
BotNameService botNameService,
|
||||
ConfigServer configServer,
|
||||
ICloner cloner
|
||||
)
|
||||
{
|
||||
_logger = logger;
|
||||
_hashUtil = hashUtil;
|
||||
_randomUtil = randomUtil;
|
||||
_timeUtil = timeUtil;
|
||||
_profileHelper = profileHelper;
|
||||
_databaseService = databaseService;
|
||||
_botInventoryGenerator = botInventoryGenerator;
|
||||
_botLevelGenerator = botLevelGenerator;
|
||||
_botEquipmentFilterService = botEquipmentFilterService;
|
||||
_weightedRandomHelper = weightedRandomHelper;
|
||||
_botHelper = botHelper;
|
||||
_botGeneratorHelper = botGeneratorHelper;
|
||||
_seasonalEventService = seasonalEventService;
|
||||
_itemFilterService = itemFilterService;
|
||||
_botNameService = botNameService;
|
||||
_configServer = configServer;
|
||||
_cloner = cloner;
|
||||
|
||||
_botConfig = _configServer.GetConfig<BotConfig>();
|
||||
_pmcConfig = _configServer.GetConfig<PmcConfig>();
|
||||
}
|
||||
protected BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
|
||||
protected PmcConfig _pmcConfig = _configServer.GetConfig<PmcConfig>();
|
||||
|
||||
/// <summary>
|
||||
/// Generate a player scav bot object
|
||||
@@ -223,7 +182,8 @@ public class BotGenerator
|
||||
var botLevel = _botLevelGenerator.GenerateBotLevel(
|
||||
botJsonTemplate.BotExperience.Level,
|
||||
botGenerationDetails,
|
||||
bot);
|
||||
bot
|
||||
);
|
||||
|
||||
// Only filter bot equipment, never players
|
||||
if (!botGenerationDetails.IsPlayerScav.GetValueOrDefault(false))
|
||||
@@ -232,14 +192,16 @@ public class BotGenerator
|
||||
sessionId,
|
||||
botJsonTemplate,
|
||||
botLevel.Level.Value,
|
||||
botGenerationDetails);
|
||||
botGenerationDetails
|
||||
);
|
||||
}
|
||||
|
||||
bot.Info.Nickname = _botNameService.GenerateUniqueBotNickname(
|
||||
botJsonTemplate,
|
||||
botGenerationDetails,
|
||||
botRoleLowercase,
|
||||
_botConfig.BotRolesThatMustHaveUniqueName);
|
||||
_botConfig.BotRolesThatMustHaveUniqueName
|
||||
);
|
||||
bot.Info.LowerNickname = bot.Info.Nickname.ToLower();
|
||||
|
||||
// Only run when generating a 'fake' playerscav, not actual player scav
|
||||
@@ -256,7 +218,8 @@ public class BotGenerator
|
||||
{
|
||||
_seasonalEventService.RemoveChristmasItemsFromBotInventory(
|
||||
botJsonTemplate.BotInventory,
|
||||
botGenerationDetails.Role);
|
||||
botGenerationDetails.Role
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,15 +236,18 @@ public class BotGenerator
|
||||
bot.Info.Settings.Experience = GetExperienceRewardForKillByDifficulty(
|
||||
botJsonTemplate.BotExperience.Reward,
|
||||
botGenerationDetails.BotDifficulty,
|
||||
botGenerationDetails.Role);
|
||||
botGenerationDetails.Role
|
||||
);
|
||||
bot.Info.Settings.StandingForKill = GetStandingChangeForKillByDifficulty(
|
||||
botJsonTemplate.BotExperience.StandingForKill,
|
||||
botGenerationDetails.BotDifficulty,
|
||||
botGenerationDetails.Role);
|
||||
botGenerationDetails.Role
|
||||
);
|
||||
bot.Info.Settings.AggressorBonus = GetAgressorBonusByDifficulty(
|
||||
botJsonTemplate.BotExperience.StandingForKill,
|
||||
botGenerationDetails.BotDifficulty,
|
||||
botGenerationDetails.Role);
|
||||
botGenerationDetails.Role
|
||||
);
|
||||
bot.Info.Settings.UseSimpleAnimator = botJsonTemplate.BotExperience.UseSimpleAnimator ?? false;
|
||||
bot.Info.Voice = _weightedRandomHelper.GetWeightedValue(botJsonTemplate.BotAppearance.Voice);
|
||||
bot.Health = GenerateHealth(botJsonTemplate.BotHealth, botGenerationDetails.IsPlayerScav.GetValueOrDefault(false));
|
||||
@@ -309,7 +275,8 @@ public class BotGenerator
|
||||
botRoleLowercase,
|
||||
botGenerationDetails.IsPmc.GetValueOrDefault(false),
|
||||
botLevel.Level.Value,
|
||||
bot.Info.GameVersion);
|
||||
bot.Info.GameVersion
|
||||
);
|
||||
|
||||
if (_botConfig.BotRolesWithDogTags.Contains(botRoleLowercase))
|
||||
{
|
||||
@@ -408,7 +375,8 @@ public class BotGenerator
|
||||
{
|
||||
var blacklist = _botEquipmentFilterService.GetBotEquipmentBlacklist(
|
||||
_botGeneratorHelper.GetBotEquipmentRole(botGenerationDetails.Role),
|
||||
botGenerationDetails.PlayerLevel.GetValueOrDefault(1));
|
||||
botGenerationDetails.PlayerLevel.GetValueOrDefault(1)
|
||||
);
|
||||
|
||||
if (blacklist?.Gear is null)
|
||||
{
|
||||
@@ -683,31 +651,35 @@ public class BotGenerator
|
||||
if (skills is null)
|
||||
return [];
|
||||
|
||||
return skills.Select(kvp =>
|
||||
{
|
||||
// Get skill from dict, skip if not found
|
||||
var skill = kvp.Value;
|
||||
if (skill == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return skills.Select(
|
||||
kvp =>
|
||||
{
|
||||
// Get skill from dict, skip if not found
|
||||
var skill = kvp.Value;
|
||||
if (skill == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// All skills have id and progress props
|
||||
var skillToAdd = new BaseSkill
|
||||
{
|
||||
Id = kvp.Key,
|
||||
Progress = _randomUtil.GetInt((int)skill.Min, (int)skill.Max)
|
||||
};
|
||||
// All skills have id and progress props
|
||||
var skillToAdd = new BaseSkill
|
||||
{
|
||||
Id = kvp.Key,
|
||||
Progress = _randomUtil.GetInt((int)skill.Min, (int)skill.Max)
|
||||
};
|
||||
|
||||
// Common skills have additional props
|
||||
if (isCommonSkills)
|
||||
{
|
||||
((Common)skillToAdd).PointsEarnedDuringSession = 0;
|
||||
((Common)skillToAdd).LastAccess = 0;
|
||||
}
|
||||
// Common skills have additional props
|
||||
if (isCommonSkills)
|
||||
{
|
||||
((Common)skillToAdd).PointsEarnedDuringSession = 0;
|
||||
((Common)skillToAdd).LastAccess = 0;
|
||||
}
|
||||
|
||||
return skillToAdd;
|
||||
}).Where(baseSkill => baseSkill != null).ToList();
|
||||
return skillToAdd;
|
||||
}
|
||||
)
|
||||
.Where(baseSkill => baseSkill != null)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -718,7 +690,7 @@ public class BotGenerator
|
||||
public void AddIdsToBot(BotBase bot)
|
||||
{
|
||||
var botId = _hashUtil.Generate();
|
||||
|
||||
|
||||
bot.Id = botId;
|
||||
bot.Aid = _hashUtil.GenerateAccountId();
|
||||
}
|
||||
@@ -732,9 +704,11 @@ public class BotGenerator
|
||||
{
|
||||
var newInventoryItemId = _hashUtil.Generate();
|
||||
|
||||
foreach (var item in profile.Inventory.Items) {
|
||||
foreach (var item in profile.Inventory.Items)
|
||||
{
|
||||
// Root item found, update its _id value to newly generated id
|
||||
if (item.Template == ItemTpl.INVENTORY_DEFAULT) {
|
||||
if (item.Template == ItemTpl.INVENTORY_DEFAULT)
|
||||
{
|
||||
item.Id = newInventoryItemId;
|
||||
|
||||
continue;
|
||||
@@ -742,12 +716,14 @@ public class BotGenerator
|
||||
|
||||
// Optimisation - skip items without a parentId
|
||||
// They are never linked to root inventory item + we already handled root item above
|
||||
if (item.ParentId is null) {
|
||||
if (item.ParentId is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Item is a child of root inventory item, update its parentId value to newly generated id
|
||||
if (item.ParentId == profile.Inventory.Equipment) {
|
||||
if (item.ParentId == profile.Inventory.Equipment)
|
||||
{
|
||||
item.ParentId = newInventoryItemId;
|
||||
}
|
||||
}
|
||||
@@ -766,7 +742,8 @@ public class BotGenerator
|
||||
public string SetRandomisedGameVersionAndCategory(Info botInfo)
|
||||
{
|
||||
// Special case
|
||||
if (botInfo.Nickname?.ToLower() == "nikita") {
|
||||
if (botInfo.Nickname?.ToLower() == "nikita")
|
||||
{
|
||||
botInfo.GameVersion = GameEditions.UNHEARD;
|
||||
botInfo.MemberCategory = MemberCategory.DEVELOPER;
|
||||
|
||||
@@ -777,7 +754,8 @@ public class BotGenerator
|
||||
botInfo.GameVersion = _weightedRandomHelper.GetWeightedValue(_pmcConfig.GameVersionWeight);
|
||||
|
||||
// Choose appropriate member category value
|
||||
switch (botInfo.GameVersion) {
|
||||
switch (botInfo.GameVersion)
|
||||
{
|
||||
case GameEditions.EDGE_OF_DARKNESS:
|
||||
botInfo.MemberCategory = MemberCategory.UNIQUE_ID;
|
||||
break;
|
||||
@@ -803,12 +781,14 @@ public class BotGenerator
|
||||
/// <returns></returns>
|
||||
public void AddDogtagToBot(BotBase bot)
|
||||
{
|
||||
Item inventoryItem = new () {
|
||||
Item inventoryItem = new()
|
||||
{
|
||||
Id = _hashUtil.Generate(),
|
||||
Template = GetDogtagTplByGameVersionAndSide(bot.Info.Side, bot.Info.GameVersion),
|
||||
ParentId = bot.Inventory.Equipment,
|
||||
SlotId = "Dogtag",
|
||||
Upd = new () {
|
||||
Upd = new()
|
||||
{
|
||||
SpawnedInSession = true,
|
||||
},
|
||||
};
|
||||
@@ -824,8 +804,10 @@ public class BotGenerator
|
||||
/// <returns>item tpl</returns>
|
||||
public string GetDogtagTplByGameVersionAndSide(string side, string gameVersion)
|
||||
{
|
||||
if (side.ToLower() == "usec") {
|
||||
switch (gameVersion) {
|
||||
if (side.ToLower() == "usec")
|
||||
{
|
||||
switch (gameVersion)
|
||||
{
|
||||
case GameEditions.EDGE_OF_DARKNESS:
|
||||
return ItemTpl.BARTER_DOGTAG_USEC_EOD;
|
||||
case GameEditions.UNHEARD:
|
||||
@@ -835,7 +817,8 @@ public class BotGenerator
|
||||
}
|
||||
}
|
||||
|
||||
switch (gameVersion) {
|
||||
switch (gameVersion)
|
||||
{
|
||||
case GameEditions.EDGE_OF_DARKNESS:
|
||||
return ItemTpl.BARTER_DOGTAG_BEAR_EOD;
|
||||
case GameEditions.UNHEARD:
|
||||
@@ -851,7 +834,8 @@ public class BotGenerator
|
||||
/// <param name="bot">Pmc object to adjust</param>
|
||||
public void SetPmcPocketsByGameVersion(BotBase bot)
|
||||
{
|
||||
if (bot.Info.GameVersion == GameEditions.UNHEARD) {
|
||||
if (bot.Info.GameVersion == GameEditions.UNHEARD)
|
||||
{
|
||||
var pockets = bot.Inventory.Items.FirstOrDefault((item) => item.SlotId == "Pockets");
|
||||
pockets.Template = ItemTpl.POCKETS_1X4_TUE;
|
||||
}
|
||||
|
||||
@@ -16,71 +16,28 @@ using Equipment = Core.Models.Eft.Common.Tables.Equipment;
|
||||
namespace Core.Generators;
|
||||
|
||||
[Injectable]
|
||||
public class BotInventoryGenerator
|
||||
public class BotInventoryGenerator(
|
||||
ISptLogger<BotInventoryGenerator> _logger,
|
||||
HashUtil _hashUtil,
|
||||
RandomUtil _randomUtil,
|
||||
DatabaseService _databaseService,
|
||||
ApplicationContext _applicationContext,
|
||||
BotWeaponGenerator _botWeaponGenerator,
|
||||
BotLootGenerator _botLootGenerator,
|
||||
BotGeneratorHelper _botGeneratorHelper,
|
||||
ProfileHelper _profileHelper,
|
||||
BotHelper _botHelper,
|
||||
WeightedRandomHelper _weightedRandomHelper,
|
||||
ItemHelper _itemHelper,
|
||||
WeatherHelper _weatherHelper,
|
||||
LocalisationService _localisationService,
|
||||
BotEquipmentFilterService _botEquipmentFilterService,
|
||||
BotEquipmentModPoolService _botEquipmentModPoolService,
|
||||
BotEquipmentModGenerator _botEquipmentModGenerator,
|
||||
ConfigServer _configServer
|
||||
)
|
||||
{
|
||||
protected ISptLogger<BotInventoryGenerator> _logger;
|
||||
protected HashUtil _hashUtil;
|
||||
protected RandomUtil _randomUtil;
|
||||
protected DatabaseService _databaseService;
|
||||
protected ApplicationContext _applicationContext;
|
||||
protected BotWeaponGenerator _botWeaponGenerator;
|
||||
protected BotLootGenerator _botLootGenerator;
|
||||
protected BotGeneratorHelper _botGeneratorHelper;
|
||||
protected ProfileHelper _profileHelper;
|
||||
protected BotHelper _botHelper;
|
||||
protected WeightedRandomHelper _weightedRandomHelper;
|
||||
protected ItemHelper _itemHelper;
|
||||
protected WeatherHelper _weatherHelper;
|
||||
protected LocalisationService _localisationService;
|
||||
protected BotEquipmentFilterService _botEquipmentFilterService;
|
||||
protected BotEquipmentModPoolService _botEquipmentModPoolService;
|
||||
protected BotEquipmentModGenerator _botEquipmentModGenerator;
|
||||
protected ConfigServer _configServer;
|
||||
|
||||
private BotConfig _botConfig;
|
||||
|
||||
public BotInventoryGenerator(
|
||||
ISptLogger<BotInventoryGenerator> logger,
|
||||
HashUtil hashUtil,
|
||||
RandomUtil randomUtil,
|
||||
DatabaseService databaseService,
|
||||
ApplicationContext applicationContext,
|
||||
BotWeaponGenerator botWeaponGenerator,
|
||||
BotLootGenerator botLootGenerator,
|
||||
BotGeneratorHelper botGeneratorHelper,
|
||||
ProfileHelper profileHelper,
|
||||
BotHelper botHelper,
|
||||
WeightedRandomHelper weightedRandomHelper,
|
||||
ItemHelper itemHelper,
|
||||
WeatherHelper weatherHelper,
|
||||
LocalisationService localisationService,
|
||||
BotEquipmentFilterService botEquipmentFilterService,
|
||||
BotEquipmentModPoolService botEquipmentModPoolService,
|
||||
BotEquipmentModGenerator botEquipmentModGenerator,
|
||||
ConfigServer configServer
|
||||
)
|
||||
{
|
||||
_logger = logger;
|
||||
_hashUtil = hashUtil;
|
||||
_randomUtil = randomUtil;
|
||||
_databaseService = databaseService;
|
||||
_applicationContext = applicationContext;
|
||||
_botWeaponGenerator = botWeaponGenerator;
|
||||
_botLootGenerator = botLootGenerator;
|
||||
_botGeneratorHelper = botGeneratorHelper;
|
||||
_profileHelper = profileHelper;
|
||||
_botHelper = botHelper;
|
||||
_weightedRandomHelper = weightedRandomHelper;
|
||||
_itemHelper = itemHelper;
|
||||
_weatherHelper = weatherHelper;
|
||||
_localisationService = localisationService;
|
||||
_botEquipmentFilterService = botEquipmentFilterService;
|
||||
_botEquipmentModPoolService = botEquipmentModPoolService;
|
||||
_botEquipmentModGenerator = botEquipmentModGenerator;
|
||||
_configServer = configServer;
|
||||
|
||||
_botConfig = _configServer.GetConfig<BotConfig>();
|
||||
}
|
||||
private BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
|
||||
|
||||
/// <summary>
|
||||
/// Add equipment/weapons/loot to bot
|
||||
@@ -114,7 +71,8 @@ public class BotInventoryGenerator
|
||||
botInventory,
|
||||
botLevel,
|
||||
chosenGameVersion,
|
||||
raidConfig);
|
||||
raidConfig
|
||||
);
|
||||
|
||||
// Roll weapon spawns (primary/secondary/holster) and generate a weapon for each roll that passed
|
||||
GenerateAndAddWeaponsToBot(
|
||||
@@ -125,7 +83,8 @@ public class BotInventoryGenerator
|
||||
botRole,
|
||||
isPmc,
|
||||
itemGenerationLimitsMinMax,
|
||||
botLevel);
|
||||
botLevel
|
||||
);
|
||||
|
||||
// Pick loot and add to bots containers (rig/backpack/pockets/secure)
|
||||
_botLootGenerator.GenerateLoot(sessionId, botJsonTemplate, isPmc, botRole, botInventory, botLevel);
|
||||
@@ -209,7 +168,9 @@ public class BotInventoryGenerator
|
||||
{
|
||||
// Never let mod chance go outside of 0 - 100
|
||||
randomistionDetails.EquipmentMods[equipmentSlotKvP.Key] = Math.Min(
|
||||
Math.Max(randomistionDetails.EquipmentMods[equipmentSlotKvP.Key] + equipmentSlotKvP.Value, 0), 100);
|
||||
Math.Max(randomistionDetails.EquipmentMods[equipmentSlotKvP.Key] + equipmentSlotKvP.Value, 0),
|
||||
100
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,10 +191,48 @@ public class BotInventoryGenerator
|
||||
continue;
|
||||
}
|
||||
|
||||
GenerateEquipment(new GenerateEquipmentProperties
|
||||
GenerateEquipment(
|
||||
new GenerateEquipmentProperties
|
||||
{
|
||||
RootEquipmentSlot = equipmentSlot,
|
||||
RootEquipmentPool = value,
|
||||
ModPool = templateInventory.Mods,
|
||||
SpawnChances = wornItemChances,
|
||||
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
||||
Inventory = botInventory,
|
||||
BotEquipmentConfig = botEquipConfig,
|
||||
RandomisationDetails = randomistionDetails,
|
||||
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Generate below in specific order
|
||||
GenerateEquipment(
|
||||
new GenerateEquipmentProperties
|
||||
{
|
||||
RootEquipmentSlot = equipmentSlot,
|
||||
RootEquipmentPool = value,
|
||||
RootEquipmentSlot = EquipmentSlots.Pockets,
|
||||
// Unheard profiles have unique sized pockets, TODO - handle this somewhere else in a better way
|
||||
RootEquipmentPool =
|
||||
chosenGameVersion == GameEditions.UNHEARD
|
||||
? new Dictionary<string, double> { [ItemTpl.POCKETS_1X4_TUE] = 1 }
|
||||
: templateInventory.Equipment[EquipmentSlots.Pockets],
|
||||
ModPool = templateInventory.Mods,
|
||||
SpawnChances = wornItemChances,
|
||||
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
||||
Inventory = botInventory,
|
||||
BotEquipmentConfig = botEquipConfig,
|
||||
RandomisationDetails = randomistionDetails,
|
||||
GenerateModsBlacklist = [ItemTpl.POCKETS_1X4_TUE],
|
||||
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
||||
}
|
||||
);
|
||||
|
||||
GenerateEquipment(
|
||||
new GenerateEquipmentProperties
|
||||
{
|
||||
RootEquipmentSlot = EquipmentSlots.FaceCover,
|
||||
RootEquipmentPool = templateInventory.Equipment[EquipmentSlots.FaceCover],
|
||||
ModPool = templateInventory.Mods,
|
||||
SpawnChances = wornItemChances,
|
||||
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
||||
@@ -241,79 +240,53 @@ public class BotInventoryGenerator
|
||||
BotEquipmentConfig = botEquipConfig,
|
||||
RandomisationDetails = randomistionDetails,
|
||||
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Generate below in specific order
|
||||
GenerateEquipment(new GenerateEquipmentProperties
|
||||
{
|
||||
RootEquipmentSlot = EquipmentSlots.Pockets,
|
||||
// Unheard profiles have unique sized pockets, TODO - handle this somewhere else in a better way
|
||||
RootEquipmentPool =
|
||||
chosenGameVersion == GameEditions.UNHEARD
|
||||
? new Dictionary<string, double> { [ItemTpl.POCKETS_1X4_TUE] = 1 }
|
||||
: templateInventory.Equipment[EquipmentSlots.Pockets],
|
||||
ModPool = templateInventory.Mods,
|
||||
SpawnChances = wornItemChances,
|
||||
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
||||
Inventory = botInventory,
|
||||
BotEquipmentConfig = botEquipConfig,
|
||||
RandomisationDetails = randomistionDetails,
|
||||
GenerateModsBlacklist = [ItemTpl.POCKETS_1X4_TUE],
|
||||
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
||||
});
|
||||
GenerateEquipment(
|
||||
new GenerateEquipmentProperties
|
||||
{
|
||||
RootEquipmentSlot = EquipmentSlots.Headwear,
|
||||
RootEquipmentPool = templateInventory.Equipment[EquipmentSlots.Headwear],
|
||||
ModPool = templateInventory.Mods,
|
||||
SpawnChances = wornItemChances,
|
||||
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
||||
Inventory = botInventory,
|
||||
BotEquipmentConfig = botEquipConfig,
|
||||
RandomisationDetails = randomistionDetails,
|
||||
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
||||
}
|
||||
);
|
||||
|
||||
GenerateEquipment(new GenerateEquipmentProperties
|
||||
{
|
||||
RootEquipmentSlot = EquipmentSlots.FaceCover,
|
||||
RootEquipmentPool = templateInventory.Equipment[EquipmentSlots.FaceCover],
|
||||
ModPool = templateInventory.Mods,
|
||||
SpawnChances = wornItemChances,
|
||||
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
||||
Inventory = botInventory,
|
||||
BotEquipmentConfig = botEquipConfig,
|
||||
RandomisationDetails = randomistionDetails,
|
||||
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
||||
});
|
||||
GenerateEquipment(
|
||||
new GenerateEquipmentProperties
|
||||
{
|
||||
RootEquipmentSlot = EquipmentSlots.Earpiece,
|
||||
RootEquipmentPool = templateInventory.Equipment[EquipmentSlots.Earpiece],
|
||||
ModPool = templateInventory.Mods,
|
||||
SpawnChances = wornItemChances,
|
||||
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
||||
Inventory = botInventory,
|
||||
BotEquipmentConfig = botEquipConfig,
|
||||
RandomisationDetails = randomistionDetails,
|
||||
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
||||
}
|
||||
);
|
||||
|
||||
GenerateEquipment(new GenerateEquipmentProperties
|
||||
{
|
||||
RootEquipmentSlot = EquipmentSlots.Headwear,
|
||||
RootEquipmentPool = templateInventory.Equipment[EquipmentSlots.Headwear],
|
||||
ModPool = templateInventory.Mods,
|
||||
SpawnChances = wornItemChances,
|
||||
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
||||
Inventory = botInventory,
|
||||
BotEquipmentConfig = botEquipConfig,
|
||||
RandomisationDetails = randomistionDetails,
|
||||
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
||||
});
|
||||
|
||||
GenerateEquipment(new GenerateEquipmentProperties
|
||||
{
|
||||
RootEquipmentSlot = EquipmentSlots.Earpiece,
|
||||
RootEquipmentPool = templateInventory.Equipment[EquipmentSlots.Earpiece],
|
||||
ModPool = templateInventory.Mods,
|
||||
SpawnChances = wornItemChances,
|
||||
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
||||
Inventory = botInventory,
|
||||
BotEquipmentConfig = botEquipConfig,
|
||||
RandomisationDetails = randomistionDetails,
|
||||
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
||||
});
|
||||
|
||||
var hasArmorVest = GenerateEquipment(new GenerateEquipmentProperties
|
||||
{
|
||||
RootEquipmentSlot = EquipmentSlots.ArmorVest,
|
||||
RootEquipmentPool = templateInventory.Equipment[EquipmentSlots.ArmorVest],
|
||||
ModPool = templateInventory.Mods,
|
||||
SpawnChances = wornItemChances,
|
||||
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
||||
Inventory = botInventory,
|
||||
BotEquipmentConfig = botEquipConfig,
|
||||
RandomisationDetails = randomistionDetails,
|
||||
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
||||
});
|
||||
var hasArmorVest = GenerateEquipment(
|
||||
new GenerateEquipmentProperties
|
||||
{
|
||||
RootEquipmentSlot = EquipmentSlots.ArmorVest,
|
||||
RootEquipmentPool = templateInventory.Equipment[EquipmentSlots.ArmorVest],
|
||||
ModPool = templateInventory.Mods,
|
||||
SpawnChances = wornItemChances,
|
||||
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
||||
Inventory = botInventory,
|
||||
BotEquipmentConfig = botEquipConfig,
|
||||
RandomisationDetails = randomistionDetails,
|
||||
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
||||
}
|
||||
);
|
||||
|
||||
// Bot has no armor vest and flagged to be forced to wear armored rig in this event
|
||||
if (botEquipConfig.ForceOnlyArmoredRigWhenNoArmor.GetValueOrDefault(false) && !hasArmorVest)
|
||||
@@ -335,18 +308,20 @@ public class BotInventoryGenerator
|
||||
wornItemChances.EquipmentChances["TacticalVest"] = 100;
|
||||
}
|
||||
|
||||
GenerateEquipment(new GenerateEquipmentProperties
|
||||
{
|
||||
RootEquipmentSlot = EquipmentSlots.Earpiece,
|
||||
RootEquipmentPool = templateInventory.Equipment[EquipmentSlots.Earpiece],
|
||||
ModPool = templateInventory.Mods,
|
||||
SpawnChances = wornItemChances,
|
||||
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
||||
Inventory = botInventory,
|
||||
BotEquipmentConfig = botEquipConfig,
|
||||
RandomisationDetails = randomistionDetails,
|
||||
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
||||
});
|
||||
GenerateEquipment(
|
||||
new GenerateEquipmentProperties
|
||||
{
|
||||
RootEquipmentSlot = EquipmentSlots.Earpiece,
|
||||
RootEquipmentPool = templateInventory.Equipment[EquipmentSlots.Earpiece],
|
||||
ModPool = templateInventory.Mods,
|
||||
SpawnChances = wornItemChances,
|
||||
BotData = new BotData { Role = botRole, Level = botLevel, EquipmentRole = botEquipmentRole },
|
||||
Inventory = botInventory,
|
||||
BotEquipmentConfig = botEquipConfig,
|
||||
RandomisationDetails = randomistionDetails,
|
||||
GeneratingPlayerLevel = pmcProfile.Info.Level,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -356,7 +331,8 @@ public class BotInventoryGenerator
|
||||
/// <param name="botRole">Role of bot vests are being filtered for</param>
|
||||
public void FilterRigsToThoseWithProtection(Dictionary<EquipmentSlots, Dictionary<string, double>> templateEquipment, string botRole)
|
||||
{
|
||||
var tacVestsWithArmor = templateEquipment[EquipmentSlots.TacticalVest].Where(kvp => _itemHelper.ItemHasSlots(kvp.Key))
|
||||
var tacVestsWithArmor = templateEquipment[EquipmentSlots.TacticalVest]
|
||||
.Where(kvp => _itemHelper.ItemHasSlots(kvp.Key))
|
||||
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||
|
||||
if (!tacVestsWithArmor.Any())
|
||||
@@ -375,9 +351,11 @@ public class BotInventoryGenerator
|
||||
/// <param name="templateEquipment">Equipment to filter TacticalVest by</param>
|
||||
/// <param name="botRole">Role of bot vests are being filtered for</param>
|
||||
/// <param name="allowEmptyResult">Should the function return all rigs when 0 unarmored are found</param>
|
||||
public void FilterRigsToThoseWithoutProtection(Dictionary<EquipmentSlots, Dictionary<string, double>> templateEquipment, string botRole, bool allowEmptyResult = true)
|
||||
public void FilterRigsToThoseWithoutProtection(Dictionary<EquipmentSlots, Dictionary<string, double>> templateEquipment, string botRole,
|
||||
bool allowEmptyResult = true)
|
||||
{
|
||||
var tacVestsWithoutArmor = templateEquipment[EquipmentSlots.TacticalVest].Where(kvp => !_itemHelper.ItemHasSlots(kvp.Key))
|
||||
var tacVestsWithoutArmor = templateEquipment[EquipmentSlots.TacticalVest]
|
||||
.Where(kvp => !_itemHelper.ItemHasSlots(kvp.Key))
|
||||
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||
|
||||
if (!allowEmptyResult && !tacVestsWithoutArmor.Any())
|
||||
@@ -404,8 +382,12 @@ public class BotInventoryGenerator
|
||||
|
||||
if (!spawnChance.HasValue)
|
||||
{
|
||||
_logger.Warning(_localisationService.GetText("bot-no_spawn_chance_defined_for_equipment_slot",
|
||||
settings.RootEquipmentSlot));
|
||||
_logger.Warning(
|
||||
_localisationService.GetText(
|
||||
"bot-no_spawn_chance_defined_for_equipment_slot",
|
||||
settings.RootEquipmentSlot
|
||||
)
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -637,14 +619,15 @@ public class BotInventoryGenerator
|
||||
isPmc,
|
||||
botLevel
|
||||
);
|
||||
|
||||
|
||||
botInventory.Items.AddRange(generatedWeapon.Weapon);
|
||||
|
||||
|
||||
_botWeaponGenerator.AddExtraMagazinesToInventory(
|
||||
generatedWeapon,
|
||||
itemGenerationWeights.Items.Magazines,
|
||||
botInventory,
|
||||
botRole);
|
||||
botRole
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,25 +11,13 @@ using Core.Utils;
|
||||
namespace Core.Generators;
|
||||
|
||||
[Injectable]
|
||||
public class BotLevelGenerator
|
||||
public class BotLevelGenerator(
|
||||
ISptLogger<BotLevelGenerator> _logger,
|
||||
RandomUtil _randomUtil,
|
||||
MathUtil _mathUtil,
|
||||
DatabaseService _databaseService
|
||||
)
|
||||
{
|
||||
protected ISptLogger<BotLevelGenerator> _logger;
|
||||
protected RandomUtil _randomUtil;
|
||||
protected MathUtil _mathUtil;
|
||||
protected DatabaseService _databaseService;
|
||||
|
||||
public BotLevelGenerator(
|
||||
ISptLogger<BotLevelGenerator> logger,
|
||||
RandomUtil randomUtil,
|
||||
MathUtil mathUtil,
|
||||
DatabaseService databaseService)
|
||||
{
|
||||
_logger = logger;
|
||||
_randomUtil = randomUtil;
|
||||
_mathUtil = mathUtil;
|
||||
_databaseService = databaseService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a randomised bot level and exp value
|
||||
/// </summary>
|
||||
@@ -44,8 +32,10 @@ public class BotLevelGenerator
|
||||
|
||||
// Get random level based on the exp table.
|
||||
int exp = 0;
|
||||
var level = int.Parse(ChooseBotLevel(botLevelRange.Min.Value, botLevelRange.Max.Value, 1, 1.15)
|
||||
.ToString()); // TODO - nasty double to string to int conversion
|
||||
var level = int.Parse(
|
||||
ChooseBotLevel(botLevelRange.Min.Value, botLevelRange.Max.Value, 1, 1.15)
|
||||
.ToString()
|
||||
); // TODO - nasty double to string to int conversion
|
||||
for (var i = 0; i < level; i++)
|
||||
{
|
||||
exp += expTable[i].Experience.Value;
|
||||
|
||||
@@ -13,63 +13,26 @@ using Core.Utils.Cloners;
|
||||
namespace Core.Generators;
|
||||
|
||||
[Injectable]
|
||||
public class BotLootGenerator
|
||||
public class BotLootGenerator(
|
||||
ISptLogger<BotLootGenerator> _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
|
||||
)
|
||||
{
|
||||
private readonly ISptLogger<BotLootGenerator> _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 readonly BotConfig _botConfig;
|
||||
private readonly PmcConfig _pmcConfig;
|
||||
|
||||
public BotLootGenerator(
|
||||
ISptLogger<BotLootGenerator> 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>();
|
||||
}
|
||||
protected BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
|
||||
protected PmcConfig _pmcConfig = _configServer.GetConfig<PmcConfig>();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -361,13 +324,12 @@ public class BotLootGenerator
|
||||
{
|
||||
// TODO - extend to other bot types
|
||||
if (!isPmc) return null;
|
||||
|
||||
|
||||
var matchingValue = _pmcConfig?.LootItemLimitsRub?.FirstOrDefault(
|
||||
minMaxValue => botLevel >= minMaxValue.Min && botLevel <= minMaxValue.Max
|
||||
);
|
||||
|
||||
return matchingValue;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -380,12 +342,11 @@ public class BotLootGenerator
|
||||
private double? GetBackpackRoubleTotalByLevel(int botLevel, bool isPmc)
|
||||
{
|
||||
if (!isPmc) return 0;
|
||||
|
||||
|
||||
var matchingValue = _pmcConfig.MaxBackpackLootTotalRub.FirstOrDefault(
|
||||
(minMaxValue) => botLevel >= minMaxValue.Min && botLevel <= minMaxValue.Max
|
||||
);
|
||||
return matchingValue?.Value;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -471,9 +432,9 @@ public class BotLootGenerator
|
||||
{
|
||||
// Loot pool has items
|
||||
var poolSize = pool.Count;
|
||||
|
||||
|
||||
if (poolSize <= 0) return;
|
||||
|
||||
|
||||
double currentTotalRub = 0;
|
||||
|
||||
var fitItemIntoContainerAttempts = 0;
|
||||
@@ -487,7 +448,7 @@ public class BotLootGenerator
|
||||
|
||||
var weightedItemTpl = _weightedRandomHelper.GetWeightedValue<string>(pool);
|
||||
var (key, itemToAddTemplate) = _itemHelper.GetItem(weightedItemTpl);
|
||||
|
||||
|
||||
if (!key)
|
||||
{
|
||||
_logger.Warning($"Unable to process item tpl: {weightedItemTpl} for slots: {equipmentSlots} on bot: {botRole}");
|
||||
@@ -628,7 +589,6 @@ public class BotLootGenerator
|
||||
var chosenStackCount = _weightedRandomHelper.GetWeightedValue<string>(_botConfig.WalletLoot.StackSizeWeight);
|
||||
List<Item> items =
|
||||
[
|
||||
|
||||
new Item
|
||||
{
|
||||
Id = _hashUtil.Generate(),
|
||||
@@ -639,8 +599,6 @@ public class BotLootGenerator
|
||||
StackObjectsCount = double.Parse(chosenStackCount)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
];
|
||||
result.Add(items);
|
||||
}
|
||||
@@ -773,18 +731,21 @@ public class BotLootGenerator
|
||||
private bool ItemHasReachedSpawnLimit(TemplateItem? itemTemplate, string botRole, ItemSpawnLimitSettings? itemSpawnLimits)
|
||||
{
|
||||
// PMCs and scavs have different sections of bot config for spawn limits
|
||||
if (itemSpawnLimits is not null && itemSpawnLimits.GlobalLimits?.Count == 0) {
|
||||
if (itemSpawnLimits is not null && itemSpawnLimits.GlobalLimits?.Count == 0)
|
||||
{
|
||||
// No items found in spawn limit, drop out
|
||||
return false;
|
||||
}
|
||||
|
||||
// No spawn limits, skipping
|
||||
if (itemSpawnLimits is null) {
|
||||
if (itemSpawnLimits is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var idToCheckFor = GetMatchingIdFromSpawnLimits(itemTemplate, itemSpawnLimits.GlobalLimits);
|
||||
if (idToCheckFor is null) {
|
||||
if (idToCheckFor is null)
|
||||
{
|
||||
// ParentId or tplid not found in spawnLimits, not a spawn limited item, skip
|
||||
return false;
|
||||
}
|
||||
@@ -793,15 +754,21 @@ public class BotLootGenerator
|
||||
itemSpawnLimits.CurrentLimits[idToCheckFor]++;
|
||||
|
||||
// Check if over limit
|
||||
if (itemSpawnLimits.CurrentLimits[idToCheckFor] > itemSpawnLimits.GlobalLimits[idToCheckFor]) {
|
||||
if (itemSpawnLimits.CurrentLimits[idToCheckFor] > itemSpawnLimits.GlobalLimits[idToCheckFor])
|
||||
{
|
||||
// Prevent edge-case of small loot pools + code trying to add limited item over and over infinitely
|
||||
if (itemSpawnLimits.CurrentLimits[idToCheckFor] > itemSpawnLimits.CurrentLimits[idToCheckFor] * 10) {
|
||||
if (itemSpawnLimits.CurrentLimits[idToCheckFor] > itemSpawnLimits.CurrentLimits[idToCheckFor] * 10)
|
||||
{
|
||||
_logger.Debug(
|
||||
_localisationService.GetText("bot-item_spawn_limit_reached_skipping_item", new {
|
||||
botRole = botRole,
|
||||
itemName = itemTemplate.Name,
|
||||
attempts = itemSpawnLimits.CurrentLimits[idToCheckFor]
|
||||
})
|
||||
_localisationService.GetText(
|
||||
"bot-item_spawn_limit_reached_skipping_item",
|
||||
new
|
||||
{
|
||||
botRole = botRole,
|
||||
itemName = itemTemplate.Name,
|
||||
attempts = itemSpawnLimits.CurrentLimits[idToCheckFor]
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
return false;
|
||||
@@ -823,8 +790,9 @@ public class BotLootGenerator
|
||||
{
|
||||
// Get all currency weights for this bot type
|
||||
var currencyWeights = _botConfig.CurrencyStackSize[botRole];
|
||||
if (currencyWeights is null) {
|
||||
currencyWeights = new ();
|
||||
if (currencyWeights is null)
|
||||
{
|
||||
currencyWeights = new();
|
||||
}
|
||||
|
||||
var currencyWeight = currencyWeights[moneyItem.Template];
|
||||
@@ -856,17 +824,19 @@ public class BotLootGenerator
|
||||
/// <returns>Dictionary of tplIds and limit</returns>
|
||||
public Dictionary<string, double> GetItemSpawnLimitsForBotType(string botRole)
|
||||
{
|
||||
if (_botHelper.IsBotPmc(botRole)) {
|
||||
if (_botHelper.IsBotPmc(botRole))
|
||||
{
|
||||
return _botConfig.ItemSpawnLimits["pmc"];
|
||||
}
|
||||
|
||||
if (_botConfig.ItemSpawnLimits[botRole.ToLower()] is not null) {
|
||||
if (_botConfig.ItemSpawnLimits[botRole.ToLower()] is not null)
|
||||
{
|
||||
return _botConfig.ItemSpawnLimits[botRole.ToLower()];
|
||||
}
|
||||
|
||||
_logger.Warning(_localisationService.GetText("bot-unable_to_find_spawn_limits_fallback_to_defaults", botRole));
|
||||
|
||||
return new ();
|
||||
|
||||
return new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -877,12 +847,14 @@ public class BotLootGenerator
|
||||
/// <returns>id as string, otherwise undefined</returns>
|
||||
public string? GetMatchingIdFromSpawnLimits(TemplateItem itemTemplate, Dictionary<string, double> spawnLimits)
|
||||
{
|
||||
if (spawnLimits.ContainsKey(itemTemplate.Id)) {
|
||||
if (spawnLimits.ContainsKey(itemTemplate.Id))
|
||||
{
|
||||
return itemTemplate.Id;
|
||||
}
|
||||
|
||||
// tplId not found in spawnLimits, check if parentId is
|
||||
if (spawnLimits.ContainsKey(itemTemplate.Parent)) {
|
||||
if (spawnLimits.ContainsKey(itemTemplate.Parent))
|
||||
{
|
||||
return itemTemplate.Parent;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,74 +16,40 @@ using Core.Utils.Cloners;
|
||||
namespace Core.Generators;
|
||||
|
||||
[Injectable(InjectionType.Singleton)]
|
||||
public class BotWeaponGenerator
|
||||
public class BotWeaponGenerator(
|
||||
ISptLogger<BotWeaponGenerator> _logger,
|
||||
HashUtil _hashUtil,
|
||||
DatabaseService _databaseService,
|
||||
ItemHelper _itemHelper,
|
||||
WeightedRandomHelper _weightedRandomHelper,
|
||||
BotGeneratorHelper _botGeneratorHelper,
|
||||
RandomUtil _randomUtil,
|
||||
BotWeaponGeneratorHelper _botWeaponGeneratorHelper,
|
||||
BotWeaponModLimitService _botWeaponModLimitService,
|
||||
BotEquipmentModGenerator _botEquipmentModGenerator,
|
||||
LocalisationService _localisationService,
|
||||
RepairService _repairService,
|
||||
ICloner _cloner,
|
||||
ConfigServer _configServer,
|
||||
IEnumerable<IInventoryMagGen> inventoryMagGenComponents
|
||||
)
|
||||
{
|
||||
private readonly ISptLogger<BotWeaponGenerator> _logger;
|
||||
private readonly HashUtil _hashUtil;
|
||||
private readonly DatabaseService _databaseService;
|
||||
private readonly ItemHelper _itemHelper;
|
||||
private readonly WeightedRandomHelper _weightedRandomHelper;
|
||||
private readonly BotGeneratorHelper _botGeneratorHelper;
|
||||
private readonly RandomUtil _randomUtil;
|
||||
private readonly BotWeaponGeneratorHelper _botWeaponGeneratorHelper;
|
||||
private readonly BotWeaponModLimitService _botWeaponModLimitService;
|
||||
private readonly BotEquipmentModGenerator _botEquipmentModGenerator;
|
||||
private readonly LocalisationService _localisationService;
|
||||
private readonly RepairService _repairService;
|
||||
private readonly ICloner _cloner;
|
||||
private readonly ConfigServer _configServer;
|
||||
private List<IInventoryMagGen> _inventoryMagGenComponents;
|
||||
protected List<IInventoryMagGen> _inventoryMagGenComponents = MagGenSetUp(inventoryMagGenComponents);
|
||||
protected BotConfig _botConfig = _configServer.GetConfig<BotConfig>();
|
||||
protected PmcConfig _pmcConfig = _configServer.GetConfig<PmcConfig>();
|
||||
protected RepairConfig _repairConfig = _configServer.GetConfig<RepairConfig>();
|
||||
protected const string _modMagazineSlotId = "mod_magazine";
|
||||
|
||||
private BotConfig _botConfig;
|
||||
private PmcConfig _pmcConfig;
|
||||
private RepairConfig _repairConfig;
|
||||
private const string _modMagazineSlotId = "mod_magazine";
|
||||
|
||||
public BotWeaponGenerator
|
||||
(
|
||||
ISptLogger<BotWeaponGenerator> logger,
|
||||
HashUtil hashUtil,
|
||||
DatabaseService databaseService,
|
||||
ItemHelper itemHelper,
|
||||
WeightedRandomHelper weightedRandomHelper,
|
||||
BotGeneratorHelper botGeneratorHelper,
|
||||
RandomUtil randomUtil,
|
||||
BotWeaponGeneratorHelper botWeaponGeneratorHelper,
|
||||
BotWeaponModLimitService botWeaponModLimitService,
|
||||
BotEquipmentModGenerator botEquipmentModGenerator,
|
||||
LocalisationService localisationService,
|
||||
RepairService repairService,
|
||||
ICloner cloner,
|
||||
ConfigServer configServer,
|
||||
IEnumerable<IInventoryMagGen> inventoryMagGenComponents
|
||||
)
|
||||
private static List<IInventoryMagGen> MagGenSetUp(IEnumerable<IInventoryMagGen> components)
|
||||
{
|
||||
_logger = logger;
|
||||
_hashUtil = hashUtil;
|
||||
_databaseService = databaseService;
|
||||
_itemHelper = itemHelper;
|
||||
_weightedRandomHelper = weightedRandomHelper;
|
||||
_botGeneratorHelper = botGeneratorHelper;
|
||||
_randomUtil = randomUtil;
|
||||
_botWeaponGeneratorHelper = botWeaponGeneratorHelper;
|
||||
_botWeaponModLimitService = botWeaponModLimitService;
|
||||
_botEquipmentModGenerator = botEquipmentModGenerator;
|
||||
_localisationService = localisationService;
|
||||
_repairService = repairService;
|
||||
_cloner = cloner;
|
||||
_configServer = configServer;
|
||||
|
||||
inventoryMagGenComponents.ToList()
|
||||
var inventoryMagGens = components.ToList();
|
||||
inventoryMagGens.ToList()
|
||||
.Sort(
|
||||
(a, b) =>
|
||||
a.GetPriority() -
|
||||
b.GetPriority()
|
||||
);
|
||||
_inventoryMagGenComponents = inventoryMagGenComponents.ToList();
|
||||
|
||||
_botConfig = _configServer.GetConfig<BotConfig>();
|
||||
_pmcConfig = _configServer.GetConfig<PmcConfig>();
|
||||
_repairConfig = _configServer.GetConfig<RepairConfig>();
|
||||
return inventoryMagGens.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
using Core.Annotations;
|
||||
using Core.Models.Eft.Common.Tables;
|
||||
using Core.Models.Spt.Config;
|
||||
using Core.Servers;
|
||||
|
||||
namespace Core.Generators;
|
||||
|
||||
[Injectable]
|
||||
public class FenceBaseAssortGenerator
|
||||
public class FenceBaseAssortGenerator(
|
||||
ConfigServer _configServer
|
||||
)
|
||||
{
|
||||
private TraderConfig _traderConfig;
|
||||
|
||||
public FenceBaseAssortGenerator()
|
||||
{
|
||||
}
|
||||
protected TraderConfig _traderConfig = _configServer.GetConfig<TraderConfig>();
|
||||
|
||||
/// <summary>
|
||||
/// Create base fence assorts dynamically and store in memory
|
||||
|
||||
@@ -7,15 +7,13 @@ using Core.Models.Spt.Config;
|
||||
namespace Core.Generators;
|
||||
|
||||
[Injectable]
|
||||
public class LocationLootGenerator
|
||||
public class LocationLootGenerator(
|
||||
|
||||
)
|
||||
{
|
||||
private LocationConfig _locationConfig;
|
||||
private SeasonalEventConfig _seasonalEventConfig;
|
||||
|
||||
public LocationLootGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
/// Create a list of container objects with randomised loot
|
||||
/// </summary>
|
||||
/// <param name="locationBase">Map base to generate containers for</param>
|
||||
|
||||
@@ -9,11 +9,9 @@ using Core.Models.Spt.Services;
|
||||
namespace Core.Generators;
|
||||
|
||||
[Injectable]
|
||||
public class LootGenerator
|
||||
public class LootGenerator(
|
||||
)
|
||||
{
|
||||
public LootGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a list of items based on configuration options parameter
|
||||
|
||||
@@ -4,11 +4,8 @@ using Core.Models.Eft.Common.Tables;
|
||||
namespace Core.Generators;
|
||||
|
||||
[Injectable]
|
||||
public class PMCLootGenerator
|
||||
public class PMCLootGenerator()
|
||||
{
|
||||
public PMCLootGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a List of loot items a PMC can have in their pockets
|
||||
|
||||
@@ -14,66 +14,26 @@ using Core.Utils.Cloners;
|
||||
namespace Core.Generators;
|
||||
|
||||
[Injectable]
|
||||
public class PlayerScavGenerator
|
||||
public class PlayerScavGenerator(
|
||||
ISptLogger<PlayerScavGenerator> _logger,
|
||||
RandomUtil _randomUtil,
|
||||
DatabaseService _databaseService,
|
||||
HashUtil _hashUtil,
|
||||
ItemHelper _itemHelper,
|
||||
BotGeneratorHelper _botGeneratorHelper,
|
||||
SaveServer _saveServer,
|
||||
ProfileHelper _profileHelper,
|
||||
BotHelper _botHelper,
|
||||
FenceService _fenceService,
|
||||
BotLootCacheService _botLootCacheService,
|
||||
LocalisationService _localisationService,
|
||||
BotGenerator _botGenerator,
|
||||
ConfigServer _configServer,
|
||||
ICloner _cloner,
|
||||
TimeUtil _timeUtil
|
||||
)
|
||||
{
|
||||
protected ISptLogger<PlayerScavGenerator> _logger;
|
||||
protected RandomUtil _randomUtil;
|
||||
protected DatabaseService _databaseService;
|
||||
protected HashUtil _hashUtil;
|
||||
protected ItemHelper _itemHelper;
|
||||
protected BotGeneratorHelper _botGeneratorHelper;
|
||||
protected SaveServer _saveServer;
|
||||
protected ProfileHelper _profileHelper;
|
||||
protected BotHelper _botHelper;
|
||||
protected FenceService _fenceService;
|
||||
protected BotLootCacheService _botLootCacheService;
|
||||
protected LocalisationService _localisationService;
|
||||
protected BotGenerator _botGenerator;
|
||||
protected ConfigServer _configServer;
|
||||
protected ICloner _cloner;
|
||||
protected TimeUtil _timeUtil;
|
||||
|
||||
private PlayerScavConfig _playerScavConfig;
|
||||
|
||||
public PlayerScavGenerator
|
||||
(
|
||||
ISptLogger<PlayerScavGenerator> logger,
|
||||
RandomUtil randomUtil,
|
||||
DatabaseService databaseService,
|
||||
HashUtil hashUtil,
|
||||
ItemHelper itemHelper,
|
||||
BotGeneratorHelper botGeneratorHelper,
|
||||
SaveServer saveServer,
|
||||
ProfileHelper profileHelper,
|
||||
BotHelper botHelper,
|
||||
FenceService fenceService,
|
||||
BotLootCacheService botLootCacheService,
|
||||
LocalisationService localisationService,
|
||||
BotGenerator botGenerator,
|
||||
ConfigServer configServer,
|
||||
ICloner cloner,
|
||||
TimeUtil timeUtil
|
||||
)
|
||||
{
|
||||
_logger = logger;
|
||||
_randomUtil = randomUtil;
|
||||
_databaseService = databaseService;
|
||||
_hashUtil = hashUtil;
|
||||
_itemHelper = itemHelper;
|
||||
_botGeneratorHelper = botGeneratorHelper;
|
||||
_saveServer = saveServer;
|
||||
_profileHelper = profileHelper;
|
||||
_botHelper = botHelper;
|
||||
_fenceService = fenceService;
|
||||
_botLootCacheService = botLootCacheService;
|
||||
_localisationService = localisationService;
|
||||
_botGenerator = botGenerator;
|
||||
_configServer = configServer;
|
||||
_cloner = cloner;
|
||||
_timeUtil = timeUtil;
|
||||
|
||||
_playerScavConfig = configServer.GetConfig<PlayerScavConfig>();
|
||||
}
|
||||
protected PlayerScavConfig _playerScavConfig = _configServer.GetConfig<PlayerScavConfig>();
|
||||
|
||||
/// <summary>
|
||||
/// Update a player profile to include a new player scav profile
|
||||
@@ -106,7 +66,8 @@ public class PlayerScavGenerator
|
||||
playerScavKarmaSettings.BotTypeForLoot.ToLower(),
|
||||
"easy",
|
||||
baseBotNode,
|
||||
pmcDataClone);
|
||||
pmcDataClone
|
||||
);
|
||||
|
||||
// Remove cached bot data after scav was generated
|
||||
_botLootCacheService.ClearCache();
|
||||
@@ -138,11 +99,15 @@ public class PlayerScavGenerator
|
||||
scavData.Encyclopedia = pmcDataClone.Encyclopedia ?? new();
|
||||
|
||||
// Add additional items to player scav as loot
|
||||
AddAdditionalLootToPlayerScavContainers(playerScavKarmaSettings.LootItemsToAddChancePercent, scavData, [
|
||||
EquipmentSlots.TacticalVest,
|
||||
EquipmentSlots.Pockets,
|
||||
EquipmentSlots.Backpack
|
||||
]);
|
||||
AddAdditionalLootToPlayerScavContainers(
|
||||
playerScavKarmaSettings.LootItemsToAddChancePercent,
|
||||
scavData,
|
||||
[
|
||||
EquipmentSlots.TacticalVest,
|
||||
EquipmentSlots.Pockets,
|
||||
EquipmentSlots.Backpack
|
||||
]
|
||||
);
|
||||
|
||||
// Remove secure container
|
||||
scavData = _profileHelper.RemoveSecureContainer(scavData);
|
||||
@@ -162,7 +127,8 @@ public class PlayerScavGenerator
|
||||
/// <param name="possibleItemsToAdd">dict of tpl + % chance to be added</param>
|
||||
/// <param name="scavData"></param>
|
||||
/// <param name="containersToAddTo">Possible slotIds to add loot to</param>
|
||||
protected void AddAdditionalLootToPlayerScavContainers(Dictionary<string, double> possibleItemsToAdd, BotBase scavData, List<EquipmentSlots> containersToAddTo)
|
||||
protected void AddAdditionalLootToPlayerScavContainers(Dictionary<string, double> possibleItemsToAdd, BotBase scavData,
|
||||
List<EquipmentSlots> containersToAddTo)
|
||||
{
|
||||
foreach (var tpl in possibleItemsToAdd)
|
||||
{
|
||||
@@ -193,7 +159,8 @@ public class PlayerScavGenerator
|
||||
itemsToAdd[0].Id,
|
||||
itemTemplate.Id,
|
||||
itemsToAdd,
|
||||
scavData.Inventory);
|
||||
scavData.Inventory
|
||||
);
|
||||
|
||||
if (result != ItemAddedResult.SUCCESS)
|
||||
_logger.Debug($"Unable to add keycard to bot. Reason: {result.ToString()}");
|
||||
@@ -252,8 +219,8 @@ public class PlayerScavGenerator
|
||||
protected void AdjustBotTemplateWithKarmaSpecificSettings(KarmaLevel karmaSettings, BotType baseBotNode)
|
||||
{
|
||||
// Adjust equipment chance values
|
||||
foreach (var equipmentKvP in karmaSettings.Modifiers.Equipment) {
|
||||
|
||||
foreach (var equipmentKvP in karmaSettings.Modifiers.Equipment)
|
||||
{
|
||||
// Adjustment value zero, nothing to do
|
||||
if (equipmentKvP.Value == 0)
|
||||
{
|
||||
@@ -287,7 +254,8 @@ public class PlayerScavGenerator
|
||||
}
|
||||
|
||||
// Blacklist equipment, keyed by equipment slot
|
||||
foreach (var equipmentBlacklistKvP in karmaSettings.EquipmentBlacklist) {
|
||||
foreach (var equipmentBlacklistKvP in karmaSettings.EquipmentBlacklist)
|
||||
{
|
||||
baseBotNode.BotInventory.Equipment.TryGetValue(equipmentBlacklistKvP.Key, out var equipmentDict);
|
||||
foreach (var itemToRemove in equipmentBlacklistKvP.Value)
|
||||
{
|
||||
@@ -309,7 +277,7 @@ public class PlayerScavGenerator
|
||||
return new()
|
||||
{
|
||||
Common = new(),
|
||||
Mastering = new (),
|
||||
Mastering = new(),
|
||||
Points = 0
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,11 +5,8 @@ using Core.Models.Eft.Common.Tables;
|
||||
namespace Core.Generators;
|
||||
|
||||
[Injectable]
|
||||
public class RagfairAssortGenerator
|
||||
public class RagfairAssortGenerator()
|
||||
{
|
||||
public RagfairAssortGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an array of arrays that can be sold on the flea
|
||||
|
||||
@@ -7,11 +7,8 @@ using Core.Models.Spt.Ragfair;
|
||||
namespace Core.Generators;
|
||||
|
||||
[Injectable]
|
||||
public class RagfairOfferGenerator
|
||||
public class RagfairOfferGenerator()
|
||||
{
|
||||
public RagfairOfferGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a flea offer and store it in the Ragfair server offers list
|
||||
|
||||
@@ -16,43 +16,19 @@ using BodyPart = Core.Models.Spt.Config.BodyPart;
|
||||
namespace Core.Generators;
|
||||
|
||||
[Injectable]
|
||||
public class RepeatableQuestGenerator
|
||||
public class RepeatableQuestGenerator(
|
||||
ISptLogger<RepeatableQuestGenerator> _logger,
|
||||
RandomUtil _randomUtil,
|
||||
HashUtil _hashUtil,
|
||||
MathUtil _mathUtil,
|
||||
RepeatableQuestHelper _repeatableQuestHelper,
|
||||
ItemHelper _itemHelper,
|
||||
RepeatableQuestRewardGenerator _repeatableQuestRewardGenerator,
|
||||
DatabaseService _databaseService,
|
||||
ConfigServer _configServer
|
||||
)
|
||||
{
|
||||
protected ISptLogger<RepeatableQuestGenerator> _logger;
|
||||
protected RandomUtil _randomUtil;
|
||||
protected HashUtil _hashUtil;
|
||||
protected MathUtil _mathUtil;
|
||||
protected RepeatableQuestHelper _repeatableQuestHelper;
|
||||
protected ItemHelper _itemHelper;
|
||||
protected RepeatableQuestRewardGenerator _repeatableQuestRewardGenerator;
|
||||
protected DatabaseService _databaseService;
|
||||
protected ConfigServer _configServer;
|
||||
protected QuestConfig _questConfig;
|
||||
|
||||
public RepeatableQuestGenerator(
|
||||
ISptLogger<RepeatableQuestGenerator> logger,
|
||||
RandomUtil randomUtil,
|
||||
HashUtil hashUtil,
|
||||
MathUtil mathUtil,
|
||||
RepeatableQuestHelper repeatableQuestHelper,
|
||||
ItemHelper itemHelper,
|
||||
RepeatableQuestRewardGenerator repeatableQuestRewardGenerator,
|
||||
DatabaseService databaseService,
|
||||
ConfigServer configServer
|
||||
)
|
||||
{
|
||||
_logger = logger;
|
||||
_randomUtil = randomUtil;
|
||||
_hashUtil = hashUtil;
|
||||
_mathUtil = mathUtil;
|
||||
_repeatableQuestHelper = repeatableQuestHelper;
|
||||
_itemHelper = itemHelper;
|
||||
_repeatableQuestRewardGenerator = repeatableQuestRewardGenerator;
|
||||
_databaseService = databaseService;
|
||||
_configServer = configServer;
|
||||
|
||||
_questConfig = _configServer.GetConfig<QuestConfig>();
|
||||
}
|
||||
protected QuestConfig _questConfig = _configServer.GetConfig<QuestConfig>();
|
||||
|
||||
/// <summary>
|
||||
/// This method is called by /GetClientRepeatableQuests/ and creates one element of quest type format (see assets/database/templates/repeatableQuests.json).
|
||||
@@ -77,7 +53,8 @@ public class RepeatableQuestGenerator
|
||||
// Get traders from whitelist and filter by quest type availability
|
||||
var traders = repeatableConfig.TraderWhitelist
|
||||
.Where(x => x.QuestTypes.Contains(questType))
|
||||
.Select(x => x.TraderId).ToList();
|
||||
.Select(x => x.TraderId)
|
||||
.ToList();
|
||||
// filter out locked traders
|
||||
traders = traders.Where(x => pmcTraderInfo[x].Unlocked.GetValueOrDefault(false)).ToList();
|
||||
var traderId = _randomUtil.DrawRandomFromList(traders).FirstOrDefault();
|
||||
@@ -115,8 +92,10 @@ public class RepeatableQuestGenerator
|
||||
var locationsConfig = repeatableConfig.Locations;
|
||||
var targetsConfig = _repeatableQuestHelper.ProbabilityObjectArray<Target, string, BossInfo>(eliminationConfig.Targets);
|
||||
var bodyPartsConfig = _repeatableQuestHelper.ProbabilityObjectArray<BodyPart, string, List<string>>(eliminationConfig.BodyParts);
|
||||
var weaponCategoryRequirementConfig = _repeatableQuestHelper.ProbabilityObjectArray<WeaponRequirement, string, List<string>>(eliminationConfig.WeaponCategoryRequirements);
|
||||
var weaponRequirementConfig = _repeatableQuestHelper.ProbabilityObjectArray<WeaponRequirement, string, List<string>>(eliminationConfig.WeaponRequirements);
|
||||
var weaponCategoryRequirementConfig =
|
||||
_repeatableQuestHelper.ProbabilityObjectArray<WeaponRequirement, string, List<string>>(eliminationConfig.WeaponCategoryRequirements);
|
||||
var weaponRequirementConfig =
|
||||
_repeatableQuestHelper.ProbabilityObjectArray<WeaponRequirement, string, List<string>>(eliminationConfig.WeaponRequirements);
|
||||
|
||||
// the difficulty of the quest varies in difficulty depending on the condition
|
||||
// possible conditions are
|
||||
@@ -171,7 +150,7 @@ public class RepeatableQuestGenerator
|
||||
var locationKey = "any";
|
||||
if (locations.Contains("any") &&
|
||||
(eliminationConfig.SpecificLocationProbability < rand.Next() || locations.Count <= 1)
|
||||
)
|
||||
)
|
||||
{
|
||||
locationKey = "any";
|
||||
questTypePool.Pool.Elimination.Targets.Remove(targetKey);
|
||||
@@ -183,7 +162,9 @@ public class RepeatableQuestGenerator
|
||||
{
|
||||
locationKey = _randomUtil.DrawRandomFromList(locations).FirstOrDefault();
|
||||
questTypePool.Pool.Elimination.Targets.Get<TargetLocation>(targetKey).Locations = locations.Where(
|
||||
(l) => l != locationKey).ToList();
|
||||
(l) => l != locationKey
|
||||
)
|
||||
.ToList();
|
||||
if (questTypePool.Pool.Elimination.Targets.Get<TargetLocation>(targetKey).Locations.Count == 0)
|
||||
{
|
||||
questTypePool.Pool.Elimination.Targets.Remove(targetKey);
|
||||
@@ -216,6 +197,7 @@ public class RepeatableQuestGenerator
|
||||
bodyPartsToClient.Add(biClient);
|
||||
}
|
||||
}
|
||||
|
||||
bodyPartDifficulty = 1 / probability;
|
||||
}
|
||||
|
||||
@@ -227,17 +209,21 @@ public class RepeatableQuestGenerator
|
||||
if (targetsConfig.Data(targetKey).IsBoss.GetValueOrDefault(false))
|
||||
{
|
||||
// Get all boss spawn information
|
||||
var bossSpawns = _databaseService.GetLocations().GetDictionary()
|
||||
var bossSpawns = _databaseService.GetLocations()
|
||||
.GetDictionary()
|
||||
.Select(x => x.Value)
|
||||
.Where(x => x.Base?.Id != null)
|
||||
.Select(x => (new { x.Base.Id, BossSpawn = x.Base.BossLocationSpawn }));
|
||||
// filter for the current boss to spawn on map
|
||||
var thisBossSpawns = bossSpawns
|
||||
.Select(x => new {
|
||||
x.Id,
|
||||
BossSpawn = x.BossSpawn
|
||||
.Where(e => e.BossName == targetKey)
|
||||
})
|
||||
.Select(
|
||||
x => new
|
||||
{
|
||||
x.Id,
|
||||
BossSpawn = x.BossSpawn
|
||||
.Where(e => e.BossName == targetKey)
|
||||
}
|
||||
)
|
||||
.Where((x) => x.BossSpawn.Count() > 0);
|
||||
// remove blacklisted locations
|
||||
var allowedSpawns = thisBossSpawns.Where((x) => !eliminationConfig.DistLocationBlacklist.Contains(x.Id));
|
||||
@@ -250,7 +236,8 @@ public class RepeatableQuestGenerator
|
||||
// Random distance with lower values more likely; simple distribution for starters...
|
||||
distance = (int)Math.Floor(
|
||||
(decimal)(Math.Abs(rand.Next(0, 1) - rand.Next(0, 1)) * (1 + eliminationConfig.MaxDistance - eliminationConfig.MinDistance) +
|
||||
eliminationConfig.MinDistance));
|
||||
eliminationConfig.MinDistance)
|
||||
);
|
||||
distance = (int)Math.Ceiling((decimal)(distance / 5)) * 5;
|
||||
distanceDifficulty = (int)(maxDistDifficulty * distance / eliminationConfig.MaxDistance);
|
||||
}
|
||||
@@ -263,16 +250,20 @@ public class RepeatableQuestGenerator
|
||||
{
|
||||
List<string> weaponTypes = ["Shotgun", "Pistol"];
|
||||
weaponCategoryRequirementConfig = (ProbabilityObjectArray<WeaponRequirement, string, List<string>>)weaponCategoryRequirementConfig
|
||||
.Where((category) => weaponTypes
|
||||
.Contains(category.Key));
|
||||
.Where(
|
||||
(category) => weaponTypes
|
||||
.Contains(category.Key)
|
||||
);
|
||||
}
|
||||
else if (distance < 20)
|
||||
{
|
||||
List<string> weaponTypes = ["MarksmanRifle", "DMR"];
|
||||
// Filter out far range weapons from close distance requirement
|
||||
weaponCategoryRequirementConfig = (ProbabilityObjectArray<WeaponRequirement, string, List<string>>)weaponCategoryRequirementConfig
|
||||
.Where((category) => weaponTypes
|
||||
.Contains(category.Key));
|
||||
.Where(
|
||||
(category) => weaponTypes
|
||||
.Contains(category.Key)
|
||||
);
|
||||
}
|
||||
|
||||
// Pick a weighted weapon category
|
||||
@@ -304,7 +295,8 @@ public class RepeatableQuestGenerator
|
||||
bodyPartDifficulty / maxBodyPartsDifficulty.Value,
|
||||
distanceDifficulty / maxDistDifficulty,
|
||||
killDifficulty / maxKillDifficulty.Value,
|
||||
allowedWeaponsCategory is not null || allowedWeapon is not null ? 1 : 0);
|
||||
allowedWeaponsCategory is not null || allowedWeapon is not null ? 1 : 0
|
||||
);
|
||||
|
||||
// Aforementioned issue makes it a bit crazy since now all easier quests give significantly lower rewards than Completion / Exploration
|
||||
// I therefore moved the mapping a bit up (from 0.2...1 to 0.5...2) so that normal difficulty still gives good reward and having the
|
||||
@@ -326,16 +318,18 @@ public class RepeatableQuestGenerator
|
||||
// Only add specific location condition if specific map selected
|
||||
if (locationKey != "any")
|
||||
{
|
||||
Enum.TryParse(typeof (ELocationName), locationKey, true, out var locationId);
|
||||
Enum.TryParse(typeof(ELocationName), locationKey, true, out var locationId);
|
||||
availableForFinishCondition.Counter.Conditions.Add(GenerateEliminationLocation(locationsConfig[(ELocationName)locationId]));
|
||||
}
|
||||
|
||||
availableForFinishCondition.Counter.Conditions.Add(
|
||||
GenerateEliminationCondition(
|
||||
targetKey,
|
||||
bodyPartsToClient,
|
||||
distance.Value,
|
||||
allowedWeapon,
|
||||
allowedWeaponsCategory)
|
||||
allowedWeaponsCategory
|
||||
)
|
||||
);
|
||||
availableForFinishCondition.Value = desiredKillCount;
|
||||
availableForFinishCondition.Id = _hashUtil.Generate();
|
||||
@@ -346,7 +340,8 @@ public class RepeatableQuestGenerator
|
||||
Math.Min(difficulty, 1),
|
||||
traderId,
|
||||
repeatableConfig,
|
||||
eliminationConfig);
|
||||
eliminationConfig
|
||||
);
|
||||
|
||||
return quest;
|
||||
}
|
||||
@@ -377,11 +372,11 @@ public class RepeatableQuestGenerator
|
||||
}
|
||||
|
||||
protected double DifficultyWeighing(
|
||||
double target,
|
||||
double bodyPart,
|
||||
int dist,
|
||||
int kill,
|
||||
int weaponRequirement)
|
||||
double target,
|
||||
double bodyPart,
|
||||
int dist,
|
||||
int kill,
|
||||
int weaponRequirement)
|
||||
{
|
||||
return Math.Sqrt(Math.Sqrt(target) + bodyPart + dist + weaponRequirement) * kill;
|
||||
}
|
||||
@@ -430,15 +425,17 @@ public class RepeatableQuestGenerator
|
||||
string? allowedWeaponCategory
|
||||
)
|
||||
{
|
||||
var killConditionProps = new QuestConditionCounterCondition{
|
||||
var killConditionProps = new QuestConditionCounterCondition
|
||||
{
|
||||
Id = _hashUtil.Generate(),
|
||||
DynamicLocale = true,
|
||||
Target = target, // e,g, "AnyPmc"
|
||||
Value = 1,
|
||||
ResetOnSessionEnd = false,
|
||||
EnemyHealthEffects = [],
|
||||
Daytime = new DaytimeCounter(){ From = 0, To = 0 },
|
||||
ConditionType = "Kills"};
|
||||
Daytime = new DaytimeCounter() { From = 0, To = 0 },
|
||||
ConditionType = "Kills"
|
||||
};
|
||||
|
||||
if (target.StartsWith("boss"))
|
||||
{
|
||||
@@ -455,7 +452,7 @@ public class RepeatableQuestGenerator
|
||||
// Don't allow distance + melee requirement
|
||||
if (distance is not null && allowedWeaponCategory != "5b5f7a0886f77409407a7f96")
|
||||
{
|
||||
killConditionProps.Distance = new CounterConditionDistance{ CompareMethod = ">=", Value = distance.Value };
|
||||
killConditionProps.Distance = new CounterConditionDistance { CompareMethod = ">=", Value = distance.Value };
|
||||
}
|
||||
|
||||
// Has specific weapon requirement
|
||||
|
||||
@@ -10,327 +10,302 @@ using Core.Services;
|
||||
using Core.Utils;
|
||||
using Core.Utils.Cloners;
|
||||
|
||||
namespace Core.Generators
|
||||
namespace Core.Generators;
|
||||
|
||||
[Injectable]
|
||||
public class RepeatableQuestRewardGenerator(
|
||||
ISptLogger<RepeatableQuestRewardGenerator> _logger,
|
||||
RandomUtil _randomUtil,
|
||||
HashUtil _hashUtil,
|
||||
MathUtil _mathUtil,
|
||||
DatabaseService _databaseService,
|
||||
ItemHelper _itemHelper,
|
||||
PresetHelper _presetHelper,
|
||||
HandbookHelper _handbookHelper,
|
||||
LocalisationService _localisationService,
|
||||
ItemFilterService _itemFilterService,
|
||||
SeasonalEventService _seasonalEventService,
|
||||
ConfigServer _configServer,
|
||||
ICloner _cloner
|
||||
)
|
||||
{
|
||||
[Injectable]
|
||||
public class RepeatableQuestRewardGenerator
|
||||
protected QuestConfig _questConfig = _configServer.GetConfig<QuestConfig>();
|
||||
|
||||
/**
|
||||
* Generate the reward for a mission. A reward can consist of:
|
||||
* - Experience
|
||||
* - Money
|
||||
* - GP coins
|
||||
* - Weapon preset
|
||||
* - Items
|
||||
* - Trader Reputation
|
||||
* - Skill level experience
|
||||
*
|
||||
* The reward is dependent on the player level as given by the wiki. The exact mapping of pmcLevel to
|
||||
* experience / money / items / trader reputation can be defined in QuestConfig.js
|
||||
*
|
||||
* There's also a random variation of the reward the spread of which can be also defined in the config
|
||||
*
|
||||
* Additionally, a scaling factor w.r.t. quest difficulty going from 0.2...1 can be used
|
||||
* @param pmcLevel Level of player reward is being generated for
|
||||
* @param difficulty Reward scaling factor from 0.2 to 1
|
||||
* @param traderId Trader reward will be given by
|
||||
* @param repeatableConfig Config for quest type (daily, weekly)
|
||||
* @param questConfig
|
||||
* @param rewardTplBlacklist OPTIONAL: list of tpls to NOT use when picking a reward
|
||||
* @returns IQuestRewards
|
||||
*/
|
||||
public QuestRewards GenerateReward(
|
||||
int pmcLevel,
|
||||
double difficulty,
|
||||
string traderId,
|
||||
RepeatableQuestConfig repeatableConfig,
|
||||
EliminationConfig eliminationConfig,
|
||||
List<string>? rewardTplBlacklist = null)
|
||||
{
|
||||
#region Ctor & Params
|
||||
// Get vars to configure rewards with
|
||||
var rewardParams = GetQuestRewardValues(repeatableConfig.RewardScaling, difficulty, pmcLevel);
|
||||
|
||||
private readonly ISptLogger<RepeatableQuestRewardGenerator> _logger;
|
||||
private readonly RandomUtil _randomUtil;
|
||||
private readonly HashUtil _hashUtil;
|
||||
private readonly MathUtil _mathUtil;
|
||||
private readonly DatabaseService _databaseService;
|
||||
private readonly ItemHelper _itemHelper;
|
||||
private readonly PresetHelper _presetHelper;
|
||||
private readonly HandbookHelper _handbookHelper;
|
||||
private readonly LocalisationService _localisationService;
|
||||
private readonly ItemFilterService _itemFilterService;
|
||||
private readonly SeasonalEventService _seasonalEventService;
|
||||
private readonly ConfigServer _configServer;
|
||||
private readonly ICloner _cloner;
|
||||
private readonly QuestConfig _questConfig;
|
||||
// Get budget to spend on item rewards (copy of raw roubles given)
|
||||
var itemRewardBudget = rewardParams.RewardRoubles;
|
||||
|
||||
public RepeatableQuestRewardGenerator
|
||||
(
|
||||
ISptLogger<RepeatableQuestRewardGenerator> logger,
|
||||
RandomUtil randomUtil,
|
||||
HashUtil hashUtil,
|
||||
MathUtil mathUtil,
|
||||
DatabaseService databaseService,
|
||||
ItemHelper itemHelper,
|
||||
PresetHelper presetHelper,
|
||||
HandbookHelper handbookHelper,
|
||||
LocalisationService localisationService,
|
||||
ItemFilterService itemFilterService,
|
||||
SeasonalEventService seasonalEventService,
|
||||
ConfigServer configServer,
|
||||
ICloner cloner
|
||||
)
|
||||
// Possible improvement -> draw trader-specific items e.g. with this.itemHelper.isOfBaseclass(val._id, ItemHelper.BASECLASS.FoodDrink)
|
||||
QuestRewards rewards = new() { Started = [], Success = [], Fail = [] };
|
||||
|
||||
// Start reward index to keep track
|
||||
var rewardIndex = -1;
|
||||
|
||||
// Add xp reward
|
||||
if (rewardParams.RewardXP > 0)
|
||||
{
|
||||
_logger = logger;
|
||||
_randomUtil = randomUtil;
|
||||
_hashUtil = hashUtil;
|
||||
_mathUtil = mathUtil;
|
||||
_databaseService = databaseService;
|
||||
_itemHelper = itemHelper;
|
||||
_presetHelper = presetHelper;
|
||||
_handbookHelper = handbookHelper;
|
||||
_localisationService = localisationService;
|
||||
_itemFilterService = itemFilterService;
|
||||
_seasonalEventService = seasonalEventService;
|
||||
_configServer = configServer;
|
||||
_cloner = cloner;
|
||||
|
||||
_questConfig = _configServer.GetConfig<QuestConfig>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/**
|
||||
* Generate the reward for a mission. A reward can consist of:
|
||||
* - Experience
|
||||
* - Money
|
||||
* - GP coins
|
||||
* - Weapon preset
|
||||
* - Items
|
||||
* - Trader Reputation
|
||||
* - Skill level experience
|
||||
*
|
||||
* The reward is dependent on the player level as given by the wiki. The exact mapping of pmcLevel to
|
||||
* experience / money / items / trader reputation can be defined in QuestConfig.js
|
||||
*
|
||||
* There's also a random variation of the reward the spread of which can be also defined in the config
|
||||
*
|
||||
* Additionally, a scaling factor w.r.t. quest difficulty going from 0.2...1 can be used
|
||||
* @param pmcLevel Level of player reward is being generated for
|
||||
* @param difficulty Reward scaling factor from 0.2 to 1
|
||||
* @param traderId Trader reward will be given by
|
||||
* @param repeatableConfig Config for quest type (daily, weekly)
|
||||
* @param questConfig
|
||||
* @param rewardTplBlacklist OPTIONAL: list of tpls to NOT use when picking a reward
|
||||
* @returns IQuestRewards
|
||||
*/
|
||||
public QuestRewards GenerateReward(
|
||||
int pmcLevel,
|
||||
double difficulty,
|
||||
string traderId,
|
||||
RepeatableQuestConfig repeatableConfig,
|
||||
EliminationConfig eliminationConfig,
|
||||
List<string>? rewardTplBlacklist = null)
|
||||
{
|
||||
// Get vars to configure rewards with
|
||||
var rewardParams = GetQuestRewardValues(repeatableConfig.RewardScaling, difficulty, pmcLevel);
|
||||
|
||||
// Get budget to spend on item rewards (copy of raw roubles given)
|
||||
var itemRewardBudget = rewardParams.RewardRoubles;
|
||||
|
||||
// Possible improvement -> draw trader-specific items e.g. with this.itemHelper.isOfBaseclass(val._id, ItemHelper.BASECLASS.FoodDrink)
|
||||
QuestRewards rewards = new() { Started = [], Success = [], Fail = [] };
|
||||
|
||||
// Start reward index to keep track
|
||||
var rewardIndex = -1;
|
||||
|
||||
// Add xp reward
|
||||
if (rewardParams.RewardXP > 0)
|
||||
{
|
||||
rewards.Success.Add(
|
||||
new()
|
||||
{
|
||||
Id = _hashUtil.Generate(),
|
||||
Unknown = false,
|
||||
GameMode = [],
|
||||
AvailableInGameEditions = [],
|
||||
Index = rewardIndex,
|
||||
Value = rewardParams.RewardXP,
|
||||
Type = RewardType.Experience
|
||||
}
|
||||
);
|
||||
rewardIndex++;
|
||||
}
|
||||
|
||||
// Add money reward
|
||||
rewards.Success.Add(GetMoneyReward(traderId, rewardParams.RewardRoubles, rewardIndex));
|
||||
rewardIndex++;
|
||||
|
||||
// Add GP coin reward
|
||||
rewards.Success.Add(GenerateItemReward(Money.GP, rewardParams.GpCoinRewardCount, rewardIndex));
|
||||
rewardIndex++;
|
||||
|
||||
// Add preset weapon to reward if checks pass
|
||||
var traderWhitelistDetails = repeatableConfig.TraderWhitelist.FirstOrDefault(
|
||||
(traderWhitelist) => traderWhitelist.TraderId == traderId
|
||||
);
|
||||
if (traderWhitelistDetails?.RewardCanBeWeapon ?? false && _randomUtil.GetChance100(traderWhitelistDetails.WeaponRewardChancePercent ?? 0)
|
||||
)
|
||||
{
|
||||
var chosenWeapon = GetRandomWeaponPresetWithinBudget(itemRewardBudget, rewardIndex);
|
||||
if (chosenWeapon is not null)
|
||||
{
|
||||
rewards.Success.Add(chosenWeapon.Value.Key);
|
||||
|
||||
// Subtract price of preset from item budget so we dont give player too much stuff
|
||||
itemRewardBudget -= (int)chosenWeapon.Value.Value;
|
||||
rewardIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
var inBudgetRewardItemPool = ChooseRewardItemsWithinBudget(repeatableConfig, itemRewardBudget, traderId);
|
||||
if (rewardTplBlacklist is not null)
|
||||
{
|
||||
// Filter reward pool of items from blacklist, only use if there's at least 1 item remaining
|
||||
var filteredRewardItemPool = inBudgetRewardItemPool.Where(
|
||||
(item) => !rewardTplBlacklist.Contains(item.Id)
|
||||
);
|
||||
if (filteredRewardItemPool.Count() > 0)
|
||||
{
|
||||
inBudgetRewardItemPool = filteredRewardItemPool.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_logger.Debug(
|
||||
$"Generating: {repeatableConfig.Name} quest for: {traderId} with budget: {itemRewardBudget} totalling: {rewardParams.RewardNumItems} items"
|
||||
);
|
||||
if (inBudgetRewardItemPool.Count > 0)
|
||||
{
|
||||
var itemsToReward = GetRewardableItemsFromPoolWithinBudget(
|
||||
inBudgetRewardItemPool,
|
||||
rewardParams.RewardNumItems,
|
||||
itemRewardBudget,
|
||||
repeatableConfig
|
||||
);
|
||||
|
||||
// Add item rewards
|
||||
foreach (var itemReward in itemsToReward)
|
||||
{
|
||||
rewards.Success.Add(GenerateItemReward(itemReward.Key.Id, itemReward.Value, rewardIndex));
|
||||
rewardIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add rep reward to rewards array
|
||||
if (rewardParams.RewardReputation > 0)
|
||||
{
|
||||
Reward reward = new()
|
||||
rewards.Success.Add(
|
||||
new()
|
||||
{
|
||||
Id = _hashUtil.Generate(),
|
||||
Unknown = false,
|
||||
GameMode = [],
|
||||
AvailableInGameEditions = [],
|
||||
Target = traderId,
|
||||
Value = rewardParams.RewardReputation,
|
||||
Type = RewardType.TraderStanding,
|
||||
Index = rewardIndex
|
||||
};
|
||||
rewards.Success.Add(reward);
|
||||
rewardIndex++;
|
||||
|
||||
_logger.Debug($"Adding: {rewardParams.RewardReputation} {traderId} trader reputation reward");
|
||||
}
|
||||
|
||||
// Chance of adding skill reward
|
||||
if (_randomUtil.GetChance100((double)rewardParams.SkillRewardChance * 100))
|
||||
{
|
||||
var targetSkill = _randomUtil.GetArrayValue(eliminationConfig.PossibleSkillRewards);
|
||||
Reward reward = new()
|
||||
{
|
||||
Id = _hashUtil.Generate(),
|
||||
Unknown = false,
|
||||
GameMode = [],
|
||||
AvailableInGameEditions = [],
|
||||
Target = targetSkill,
|
||||
Value = rewardParams.SkillPointReward,
|
||||
Type = RewardType.Skill,
|
||||
Index = rewardIndex
|
||||
};
|
||||
rewards.Success.Add(reward);
|
||||
|
||||
_logger.Debug($"Adding {rewardParams.SkillPointReward} skill points to {targetSkill}");
|
||||
}
|
||||
|
||||
return rewards;
|
||||
Index = rewardIndex,
|
||||
Value = rewardParams.RewardXP,
|
||||
Type = RewardType.Experience
|
||||
}
|
||||
);
|
||||
rewardIndex++;
|
||||
}
|
||||
|
||||
private QuestRewardValues GetQuestRewardValues(RewardScaling? rewardScaling, double? difficulty, int pmcLevel)
|
||||
// Add money reward
|
||||
rewards.Success.Add(GetMoneyReward(traderId, rewardParams.RewardRoubles, rewardIndex));
|
||||
rewardIndex++;
|
||||
|
||||
// Add GP coin reward
|
||||
rewards.Success.Add(GenerateItemReward(Money.GP, rewardParams.GpCoinRewardCount, rewardIndex));
|
||||
rewardIndex++;
|
||||
|
||||
// Add preset weapon to reward if checks pass
|
||||
var traderWhitelistDetails = repeatableConfig.TraderWhitelist.FirstOrDefault(
|
||||
(traderWhitelist) => traderWhitelist.TraderId == traderId
|
||||
);
|
||||
if (traderWhitelistDetails?.RewardCanBeWeapon ?? false && _randomUtil.GetChance100(traderWhitelistDetails.WeaponRewardChancePercent ?? 0)
|
||||
)
|
||||
{
|
||||
// difficulty could go from 0.2 ... -> for lowest difficulty receive 0.2*nominal reward
|
||||
var levelsConfig = rewardScaling.Levels;
|
||||
var roublesConfig = rewardScaling.Roubles;
|
||||
var gpCoinConfig = rewardScaling.GpCoins;
|
||||
var xpConfig = rewardScaling.Experience;
|
||||
var itemsConfig = rewardScaling.Items;
|
||||
var rewardSpreadConfig = rewardScaling.RewardSpread;
|
||||
var skillRewardChanceConfig = rewardScaling.SkillRewardChance;
|
||||
var skillPointRewardConfig = rewardScaling.SkillPointReward;
|
||||
var reputationConfig = rewardScaling.Reputation;
|
||||
|
||||
var effectiveDifficulty = difficulty is null ? 1 : difficulty;
|
||||
if (difficulty is null)
|
||||
var chosenWeapon = GetRandomWeaponPresetWithinBudget(itemRewardBudget, rewardIndex);
|
||||
if (chosenWeapon is not null)
|
||||
{
|
||||
_logger.Warning(_localisationService.GetText("repeatable-difficulty_was_nan"));
|
||||
}
|
||||
rewards.Success.Add(chosenWeapon.Value.Key);
|
||||
|
||||
return new () {
|
||||
SkillPointReward = _mathUtil.Interp1(pmcLevel, levelsConfig, skillPointRewardConfig),
|
||||
SkillRewardChance = _mathUtil.Interp1(pmcLevel, levelsConfig, skillRewardChanceConfig),
|
||||
RewardReputation = GetRewardRep(effectiveDifficulty, pmcLevel, levelsConfig, reputationConfig, rewardSpreadConfig),
|
||||
RewardNumItems = GetRewardNumItems(pmcLevel, levelsConfig, itemsConfig),
|
||||
RewardRoubles = GetRewardRoubles(effectiveDifficulty, pmcLevel, levelsConfig, roublesConfig, rewardSpreadConfig),
|
||||
GpCoinRewardCount = GetGpCoinRewardCount(effectiveDifficulty, pmcLevel, levelsConfig, gpCoinConfig, rewardSpreadConfig),
|
||||
RewardXP = GetRewardXp(effectiveDifficulty, pmcLevel, levelsConfig, xpConfig, rewardSpreadConfig),
|
||||
// Subtract price of preset from item budget so we dont give player too much stuff
|
||||
itemRewardBudget -= (int)chosenWeapon.Value.Value;
|
||||
rewardIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
var inBudgetRewardItemPool = ChooseRewardItemsWithinBudget(repeatableConfig, itemRewardBudget, traderId);
|
||||
if (rewardTplBlacklist is not null)
|
||||
{
|
||||
// Filter reward pool of items from blacklist, only use if there's at least 1 item remaining
|
||||
var filteredRewardItemPool = inBudgetRewardItemPool.Where(
|
||||
(item) => !rewardTplBlacklist.Contains(item.Id)
|
||||
);
|
||||
if (filteredRewardItemPool.Count() > 0)
|
||||
{
|
||||
inBudgetRewardItemPool = filteredRewardItemPool.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_logger.Debug(
|
||||
$"Generating: {repeatableConfig.Name} quest for: {traderId} with budget: {itemRewardBudget} totalling: {rewardParams.RewardNumItems} items"
|
||||
);
|
||||
if (inBudgetRewardItemPool.Count > 0)
|
||||
{
|
||||
var itemsToReward = GetRewardableItemsFromPoolWithinBudget(
|
||||
inBudgetRewardItemPool,
|
||||
rewardParams.RewardNumItems,
|
||||
itemRewardBudget,
|
||||
repeatableConfig
|
||||
);
|
||||
|
||||
// Add item rewards
|
||||
foreach (var itemReward in itemsToReward)
|
||||
{
|
||||
rewards.Success.Add(GenerateItemReward(itemReward.Key.Id, itemReward.Value, rewardIndex));
|
||||
rewardIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add rep reward to rewards array
|
||||
if (rewardParams.RewardReputation > 0)
|
||||
{
|
||||
Reward reward = new()
|
||||
{
|
||||
Id = _hashUtil.Generate(),
|
||||
Unknown = false,
|
||||
GameMode = [],
|
||||
AvailableInGameEditions = [],
|
||||
Target = traderId,
|
||||
Value = rewardParams.RewardReputation,
|
||||
Type = RewardType.TraderStanding,
|
||||
Index = rewardIndex
|
||||
};
|
||||
rewards.Success.Add(reward);
|
||||
rewardIndex++;
|
||||
|
||||
_logger.Debug($"Adding: {rewardParams.RewardReputation} {traderId} trader reputation reward");
|
||||
}
|
||||
|
||||
private double GetRewardXp(double? effectiveDifficulty, int pmcLevel, List<double>? levelsConfig, List<double>? xpConfig, double? rewardSpreadConfig)
|
||||
// Chance of adding skill reward
|
||||
if (_randomUtil.GetChance100((double)rewardParams.SkillRewardChance * 100))
|
||||
{
|
||||
return Math.Floor((effectiveDifficulty
|
||||
* _mathUtil.Interp1(pmcLevel, levelsConfig, xpConfig)
|
||||
* _randomUtil.GetFloat((float)(1 - rewardSpreadConfig), (float)(1 + rewardSpreadConfig)))
|
||||
?? 0);
|
||||
var targetSkill = _randomUtil.GetArrayValue(eliminationConfig.PossibleSkillRewards);
|
||||
Reward reward = new()
|
||||
{
|
||||
Id = _hashUtil.Generate(),
|
||||
Unknown = false,
|
||||
GameMode = [],
|
||||
AvailableInGameEditions = [],
|
||||
Target = targetSkill,
|
||||
Value = rewardParams.SkillPointReward,
|
||||
Type = RewardType.Skill,
|
||||
Index = rewardIndex
|
||||
};
|
||||
rewards.Success.Add(reward);
|
||||
|
||||
_logger.Debug($"Adding {rewardParams.SkillPointReward} skill points to {targetSkill}");
|
||||
}
|
||||
|
||||
private double GetGpCoinRewardCount(double? effectiveDifficulty, int pmcLevel, List<double>? levelsConfig, List<double>? gpCoinConfig,
|
||||
double? rewardSpreadConfig)
|
||||
return rewards;
|
||||
}
|
||||
|
||||
private QuestRewardValues GetQuestRewardValues(RewardScaling? rewardScaling, double? difficulty, int pmcLevel)
|
||||
{
|
||||
// difficulty could go from 0.2 ... -> for lowest difficulty receive 0.2*nominal reward
|
||||
var levelsConfig = rewardScaling.Levels;
|
||||
var roublesConfig = rewardScaling.Roubles;
|
||||
var gpCoinConfig = rewardScaling.GpCoins;
|
||||
var xpConfig = rewardScaling.Experience;
|
||||
var itemsConfig = rewardScaling.Items;
|
||||
var rewardSpreadConfig = rewardScaling.RewardSpread;
|
||||
var skillRewardChanceConfig = rewardScaling.SkillRewardChance;
|
||||
var skillPointRewardConfig = rewardScaling.SkillPointReward;
|
||||
var reputationConfig = rewardScaling.Reputation;
|
||||
|
||||
var effectiveDifficulty = difficulty is null ? 1 : difficulty;
|
||||
if (difficulty is null)
|
||||
{
|
||||
return Math.Ceiling((effectiveDifficulty
|
||||
* _mathUtil.Interp1(pmcLevel, levelsConfig, gpCoinConfig)
|
||||
* _randomUtil.GetFloat((float)(1 - rewardSpreadConfig), (float)(1 + rewardSpreadConfig)))
|
||||
?? 0);
|
||||
_logger.Warning(_localisationService.GetText("repeatable-difficulty_was_nan"));
|
||||
}
|
||||
|
||||
private double GetRewardRep(double? effectiveDifficulty, int pmcLevel, List<double>? levelsConfig, List<double>? reputationConfig, double? rewardSpreadConfig)
|
||||
return new()
|
||||
{
|
||||
return Math.Round(100 * effectiveDifficulty
|
||||
* _mathUtil.Interp1(pmcLevel, levelsConfig, reputationConfig)
|
||||
* _randomUtil.GetFloat((float)(1 - rewardSpreadConfig), (float)(1 + rewardSpreadConfig))
|
||||
?? 0) / 100;
|
||||
}
|
||||
SkillPointReward = _mathUtil.Interp1(pmcLevel, levelsConfig, skillPointRewardConfig),
|
||||
SkillRewardChance = _mathUtil.Interp1(pmcLevel, levelsConfig, skillRewardChanceConfig),
|
||||
RewardReputation = GetRewardRep(effectiveDifficulty, pmcLevel, levelsConfig, reputationConfig, rewardSpreadConfig),
|
||||
RewardNumItems = GetRewardNumItems(pmcLevel, levelsConfig, itemsConfig),
|
||||
RewardRoubles = GetRewardRoubles(effectiveDifficulty, pmcLevel, levelsConfig, roublesConfig, rewardSpreadConfig),
|
||||
GpCoinRewardCount = GetGpCoinRewardCount(effectiveDifficulty, pmcLevel, levelsConfig, gpCoinConfig, rewardSpreadConfig),
|
||||
RewardXP = GetRewardXp(effectiveDifficulty, pmcLevel, levelsConfig, xpConfig, rewardSpreadConfig),
|
||||
};
|
||||
}
|
||||
|
||||
private double GetRewardNumItems(int pmcLevel, List<double>? levelsConfig, List<double>? itemsConfig)
|
||||
{
|
||||
return _randomUtil.RandInt(1, (int)Math.Round(_mathUtil.Interp1(pmcLevel, levelsConfig, itemsConfig) ?? 0) + 1);
|
||||
}
|
||||
private double GetRewardXp(double? effectiveDifficulty, int pmcLevel, List<double>? levelsConfig, List<double>? xpConfig, double? rewardSpreadConfig)
|
||||
{
|
||||
return Math.Floor(
|
||||
(effectiveDifficulty *
|
||||
_mathUtil.Interp1(pmcLevel, levelsConfig, xpConfig) *
|
||||
_randomUtil.GetFloat((float)(1 - rewardSpreadConfig), (float)(1 + rewardSpreadConfig))) ??
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
private double GetRewardRoubles(double? effectiveDifficulty, int pmcLevel, List<double>? levelsConfig, List<double>? roublesConfig, double? rewardSpreadConfig)
|
||||
{
|
||||
return Math.Floor((effectiveDifficulty
|
||||
* _mathUtil.Interp1(pmcLevel, levelsConfig, roublesConfig)
|
||||
* _randomUtil.GetFloat((float)(1 - rewardSpreadConfig), (float)(1 + rewardSpreadConfig)))
|
||||
?? 0);
|
||||
}
|
||||
private double GetGpCoinRewardCount(double? effectiveDifficulty, int pmcLevel, List<double>? levelsConfig, List<double>? gpCoinConfig,
|
||||
double? rewardSpreadConfig)
|
||||
{
|
||||
return Math.Ceiling(
|
||||
(effectiveDifficulty *
|
||||
_mathUtil.Interp1(pmcLevel, levelsConfig, gpCoinConfig) *
|
||||
_randomUtil.GetFloat((float)(1 - rewardSpreadConfig), (float)(1 + rewardSpreadConfig))) ??
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
private List<KeyValuePair<TemplateItem, double>> GetRewardableItemsFromPoolWithinBudget(List<TemplateItem> inBudgetRewardItemPool,
|
||||
object rewardNumItems, double? itemRewardBudget, RepeatableQuestConfig repeatableConfig)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
private double GetRewardRep(double? effectiveDifficulty, int pmcLevel, List<double>? levelsConfig, List<double>? reputationConfig,
|
||||
double? rewardSpreadConfig)
|
||||
{
|
||||
return Math.Round(
|
||||
100 *
|
||||
effectiveDifficulty *
|
||||
_mathUtil.Interp1(pmcLevel, levelsConfig, reputationConfig) *
|
||||
_randomUtil.GetFloat((float)(1 - rewardSpreadConfig), (float)(1 + rewardSpreadConfig)) ??
|
||||
0
|
||||
) /
|
||||
100;
|
||||
}
|
||||
|
||||
private List<TemplateItem> ChooseRewardItemsWithinBudget(RepeatableQuestConfig repeatableConfig, double? itemRewardBudget, string traderId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
private double GetRewardNumItems(int pmcLevel, List<double>? levelsConfig, List<double>? itemsConfig)
|
||||
{
|
||||
return _randomUtil.RandInt(1, (int)Math.Round(_mathUtil.Interp1(pmcLevel, levelsConfig, itemsConfig) ?? 0) + 1);
|
||||
}
|
||||
|
||||
private KeyValuePair<Reward, double>? GetRandomWeaponPresetWithinBudget(double? itemRewardBudget, double rewardIndex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
private double GetRewardRoubles(double? effectiveDifficulty, int pmcLevel, List<double>? levelsConfig, List<double>? roublesConfig,
|
||||
double? rewardSpreadConfig)
|
||||
{
|
||||
return Math.Floor(
|
||||
(effectiveDifficulty *
|
||||
_mathUtil.Interp1(pmcLevel, levelsConfig, roublesConfig) *
|
||||
_randomUtil.GetFloat((float)(1 - rewardSpreadConfig), (float)(1 + rewardSpreadConfig))) ??
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
private Reward GenerateItemReward(string d235b4d86f7742e017bc88a, object gpCoinRewardCount, double rewardIndex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
private List<KeyValuePair<TemplateItem, double>> GetRewardableItemsFromPoolWithinBudget(List<TemplateItem> inBudgetRewardItemPool,
|
||||
object rewardNumItems, double? itemRewardBudget, RepeatableQuestConfig repeatableConfig)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private Reward GetMoneyReward(string traderId, object rewardRoubles, double rewardIndex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
private List<TemplateItem> ChooseRewardItemsWithinBudget(RepeatableQuestConfig repeatableConfig, double? itemRewardBudget, string traderId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private KeyValuePair<Reward, double>? GetRandomWeaponPresetWithinBudget(double? itemRewardBudget, double rewardIndex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private Reward GenerateItemReward(string d235b4d86f7742e017bc88a, object gpCoinRewardCount, double rewardIndex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private Reward GetMoneyReward(string traderId, object rewardRoubles, double rewardIndex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
public Dictionary<string, List<TemplateItem>> GetRewardableItems(RepeatableQuestConfig repeatableConfig, string traderId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public Dictionary<string, List<TemplateItem>> GetRewardableItems(RepeatableQuestConfig repeatableConfig, string traderId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,8 @@ using Core.Models.Spt.Hideout;
|
||||
namespace Core.Generators;
|
||||
|
||||
[Injectable]
|
||||
public class ScavCaseRewardGenerator
|
||||
public class ScavCaseRewardGenerator()
|
||||
{
|
||||
public ScavCaseRewardGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an array of rewards that will be given to the player upon completing their scav case build
|
||||
|
||||
@@ -5,21 +5,11 @@ using Core.Utils;
|
||||
namespace Core.Generators.WeaponGen.Implementations;
|
||||
|
||||
[Injectable]
|
||||
public class BarrelInvetoryMagGen : InventoryMagGen, IInventoryMagGen
|
||||
public class BarrelInvetoryMagGen(
|
||||
RandomUtil _randomUtil,
|
||||
BotWeaponGeneratorHelper _botWeaponGeneratorHelper
|
||||
) : InventoryMagGen, IInventoryMagGen
|
||||
{
|
||||
private readonly RandomUtil _randomUtil;
|
||||
private readonly BotWeaponGeneratorHelper _botWeaponGeneratorHelper;
|
||||
|
||||
public BarrelInvetoryMagGen
|
||||
(
|
||||
RandomUtil randomUtil,
|
||||
BotWeaponGeneratorHelper botWeaponGeneratorHelper
|
||||
)
|
||||
{
|
||||
_randomUtil = randomUtil;
|
||||
_botWeaponGeneratorHelper = botWeaponGeneratorHelper;
|
||||
}
|
||||
|
||||
public int GetPriority()
|
||||
{
|
||||
return 50;
|
||||
|
||||
@@ -9,32 +9,15 @@ using Core.Utils;
|
||||
namespace Core.Generators.WeaponGen.Implementations;
|
||||
|
||||
[Injectable]
|
||||
public class ExternalInventoryMagGen : InventoryMagGen, IInventoryMagGen
|
||||
public class ExternalInventoryMagGen(
|
||||
ISptLogger<ExternalInventoryMagGen> _logger,
|
||||
ItemHelper _itemHelper,
|
||||
LocalisationService _localisationService,
|
||||
BotWeaponGeneratorHelper _botWeaponGeneratorHelper,
|
||||
BotGeneratorHelper _botGeneratorHelper,
|
||||
RandomUtil _randomUtil
|
||||
) : InventoryMagGen, IInventoryMagGen
|
||||
{
|
||||
private readonly ISptLogger<ExternalInventoryMagGen> _logger;
|
||||
private readonly ItemHelper _itemHelper;
|
||||
private readonly LocalisationService _localisationService;
|
||||
private readonly BotWeaponGeneratorHelper _botWeaponGeneratorHelper;
|
||||
private readonly BotGeneratorHelper _botGeneratorHelper;
|
||||
private readonly RandomUtil _randomUtil;
|
||||
|
||||
public ExternalInventoryMagGen
|
||||
(
|
||||
ISptLogger<ExternalInventoryMagGen> logger,
|
||||
ItemHelper itemHelper,
|
||||
LocalisationService localisationService,
|
||||
BotWeaponGeneratorHelper botWeaponGeneratorHelper,
|
||||
BotGeneratorHelper botGeneratorHelper,
|
||||
RandomUtil randomUtil
|
||||
)
|
||||
{
|
||||
_logger = logger;
|
||||
_itemHelper = itemHelper;
|
||||
_localisationService = localisationService;
|
||||
_botWeaponGeneratorHelper = botWeaponGeneratorHelper;
|
||||
_botGeneratorHelper = botGeneratorHelper;
|
||||
_randomUtil = randomUtil;
|
||||
}
|
||||
|
||||
public int GetPriority()
|
||||
{
|
||||
@@ -58,7 +41,8 @@ public class ExternalInventoryMagGen : InventoryMagGen, IInventoryMagGen
|
||||
List<string> attemptedMagBlacklist = [];
|
||||
var defaultMagazineTpl = _botWeaponGeneratorHelper.GetWeaponsDefaultMagazineTpl(weapon);
|
||||
var randomizedMagazineCount = _botWeaponGeneratorHelper.GetRandomizedMagazineCount(inventoryMagGen.GetMagCount());
|
||||
for (var i = 0; i < randomizedMagazineCount; i++) {
|
||||
for (var i = 0; i < randomizedMagazineCount; i++)
|
||||
{
|
||||
var magazineWithAmmo = _botWeaponGeneratorHelper.CreateMagazineWithAmmo(
|
||||
magazineTpl,
|
||||
inventoryMagGen.GetAmmoTemplate().Id,
|
||||
@@ -73,15 +57,18 @@ public class ExternalInventoryMagGen : InventoryMagGen, IInventoryMagGen
|
||||
inventoryMagGen.GetPmcInventory()
|
||||
);
|
||||
|
||||
if (fitsIntoInventory == ItemAddedResult.NO_CONTAINERS) {
|
||||
if (fitsIntoInventory == ItemAddedResult.NO_CONTAINERS)
|
||||
{
|
||||
// No containers to fit magazines, stop trying
|
||||
break;
|
||||
}
|
||||
|
||||
// No space for magazine and we haven't reached desired magazine count
|
||||
if (fitsIntoInventory == ItemAddedResult.NO_SPACE && i < randomizedMagazineCount) {
|
||||
if (fitsIntoInventory == ItemAddedResult.NO_SPACE && i < randomizedMagazineCount)
|
||||
{
|
||||
// Prevent infinite loop by only allowing 5 attempts at fitting a magazine into inventory
|
||||
if (fitAttempts > 5) {
|
||||
if (fitAttempts > 5)
|
||||
{
|
||||
_logger.Debug($"Failed {fitAttempts} times to add magazine {magazineTpl} to bot inventory, stopping");
|
||||
|
||||
break;
|
||||
@@ -91,7 +78,8 @@ public class ExternalInventoryMagGen : InventoryMagGen, IInventoryMagGen
|
||||
* so we fallback to default magazine and try again.
|
||||
* Temporary workaround to Killa spawning with no extra mags if he spawns with a drum mag */
|
||||
|
||||
if (magazineTpl == defaultMagazineTpl) {
|
||||
if (magazineTpl == defaultMagazineTpl)
|
||||
{
|
||||
// We were already on default - stop here to prevent infinite looping
|
||||
break;
|
||||
}
|
||||
@@ -102,7 +90,8 @@ public class ExternalInventoryMagGen : InventoryMagGen, IInventoryMagGen
|
||||
// Set chosen magazine tpl to the weapons default magazine tpl and try to fit into inventory next loop
|
||||
magazineTpl = defaultMagazineTpl;
|
||||
magTemplate = _itemHelper.GetItem(magazineTpl).Value;
|
||||
if (magTemplate is null) {
|
||||
if (magTemplate is null)
|
||||
{
|
||||
_logger.Error(
|
||||
_localisationService.GetText("bot-unable_to_find_default_magazine_item", magazineTpl)
|
||||
);
|
||||
@@ -111,12 +100,14 @@ public class ExternalInventoryMagGen : InventoryMagGen, IInventoryMagGen
|
||||
}
|
||||
|
||||
// Edge case - some weapons (SKS) have an internal magazine as default, choose random non-internal magazine to add to bot instead
|
||||
if (magTemplate.Properties.ReloadMagType == "InternalMagazine") {
|
||||
if (magTemplate.Properties.ReloadMagType == "InternalMagazine")
|
||||
{
|
||||
var result = GetRandomExternalMagazineForInternalMagazineGun(
|
||||
inventoryMagGen.GetWeaponTemplate().Id,
|
||||
attemptedMagBlacklist
|
||||
);
|
||||
if (result?.Id is null) {
|
||||
if (result?.Id is null)
|
||||
{
|
||||
_logger.Debug($"Unable to add additional magazine into bot inventory for weapon: {weapon.Name}, attempted: {fitAttempts} times");
|
||||
|
||||
break;
|
||||
@@ -131,7 +122,8 @@ public class ExternalInventoryMagGen : InventoryMagGen, IInventoryMagGen
|
||||
i--;
|
||||
}
|
||||
|
||||
if (fitsIntoInventory == ItemAddedResult.SUCCESS) {
|
||||
if (fitsIntoInventory == ItemAddedResult.SUCCESS)
|
||||
{
|
||||
// Reset fit counter now it succeeded
|
||||
fitAttempts = 0;
|
||||
}
|
||||
@@ -142,21 +134,26 @@ public class ExternalInventoryMagGen : InventoryMagGen, IInventoryMagGen
|
||||
{
|
||||
// The mag Slot data for the weapon
|
||||
var magSlot = _itemHelper.GetItem(weaponTpl).Value.Properties.Slots.FirstOrDefault((x) => x.Name == "mod_magazine");
|
||||
if (magSlot is null) {
|
||||
if (magSlot is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// All possible mags that fit into the weapon excluding blacklisted
|
||||
var magazinePool = magSlot.Props.Filters[0].Filter.Where((x) => !magazineBlacklist.Contains(x)).Select(
|
||||
(x) => _itemHelper.GetItem(x).Value
|
||||
);
|
||||
if (magazinePool is null) {
|
||||
var magazinePool = magSlot.Props.Filters[0]
|
||||
.Filter.Where((x) => !magazineBlacklist.Contains(x))
|
||||
.Select(
|
||||
(x) => _itemHelper.GetItem(x).Value
|
||||
);
|
||||
if (magazinePool is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Non-internal magazines that fit into the weapon
|
||||
var externalMagazineOnlyPool = magazinePool.Where((x) => x.Properties.ReloadMagType != "InternalMagazine");
|
||||
if (externalMagazineOnlyPool is null || externalMagazineOnlyPool?.Count() == 0) {
|
||||
if (externalMagazineOnlyPool is null || externalMagazineOnlyPool?.Count() == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,18 +4,10 @@ using Core.Helpers;
|
||||
namespace Core.Generators.WeaponGen.Implementations;
|
||||
|
||||
[Injectable]
|
||||
public class InternalMagazineInventoryMagGen : InventoryMagGen, IInventoryMagGen
|
||||
public class InternalMagazineInventoryMagGen(
|
||||
BotWeaponGeneratorHelper _botWeaponGeneratorHelper
|
||||
) : InventoryMagGen, IInventoryMagGen
|
||||
{
|
||||
private readonly BotWeaponGeneratorHelper _botWeaponGeneratorHelper;
|
||||
|
||||
public InternalMagazineInventoryMagGen
|
||||
(
|
||||
BotWeaponGeneratorHelper botWeaponGeneratorHelper
|
||||
)
|
||||
{
|
||||
_botWeaponGeneratorHelper = botWeaponGeneratorHelper;
|
||||
}
|
||||
|
||||
public int GetPriority()
|
||||
{
|
||||
return 0;
|
||||
@@ -35,7 +27,7 @@ public class InternalMagazineInventoryMagGen : InventoryMagGen, IInventoryMagGen
|
||||
_botWeaponGeneratorHelper.AddAmmoIntoEquipmentSlots(
|
||||
inventoryMagGen.GetAmmoTemplate().Id,
|
||||
(int)bulletCount,
|
||||
inventoryMagGen.GetPmcInventory(),
|
||||
inventoryMagGen.GetPmcInventory(),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,18 +5,11 @@ using Core.Models.Enums;
|
||||
namespace Core.Generators.WeaponGen.Implementations;
|
||||
|
||||
[Injectable]
|
||||
public class UbglExternalMagGen : InventoryMagGen, IInventoryMagGen
|
||||
public class UbglExternalMagGen(
|
||||
BotWeaponGeneratorHelper _botWeaponGeneratorHelper
|
||||
|
||||
) : InventoryMagGen, IInventoryMagGen
|
||||
{
|
||||
private readonly BotWeaponGeneratorHelper _botWeaponGeneratorHelper;
|
||||
|
||||
public UbglExternalMagGen
|
||||
(
|
||||
BotWeaponGeneratorHelper botWeaponGeneratorHelper
|
||||
)
|
||||
{
|
||||
_botWeaponGeneratorHelper = botWeaponGeneratorHelper;
|
||||
}
|
||||
|
||||
public int GetPriority()
|
||||
{
|
||||
return 1;
|
||||
|
||||
@@ -4,7 +4,7 @@ using Core.Models.Eft.Common.Tables;
|
||||
namespace Core.Generators.WeaponGen;
|
||||
|
||||
[Injectable]
|
||||
public class InventoryMagGen
|
||||
public class InventoryMagGen()
|
||||
{
|
||||
private GenerationData _magCounts;
|
||||
private TemplateItem _magazineTemplate;
|
||||
@@ -12,10 +12,6 @@ public class InventoryMagGen
|
||||
private TemplateItem _ammoTemplate;
|
||||
private BotBaseInventory _pmcInventory;
|
||||
|
||||
public InventoryMagGen()
|
||||
{
|
||||
}
|
||||
|
||||
public InventoryMagGen
|
||||
(
|
||||
GenerationData magCounts,
|
||||
@@ -23,7 +19,7 @@ public class InventoryMagGen
|
||||
TemplateItem weaponTemplate,
|
||||
TemplateItem ammoTemplate,
|
||||
BotBaseInventory pmcInventory
|
||||
)
|
||||
) : this()
|
||||
{
|
||||
_magCounts = magCounts;
|
||||
_magazineTemplate = magazineTemplate;
|
||||
|
||||
@@ -10,34 +10,16 @@ using Core.Utils;
|
||||
namespace Core.Generators;
|
||||
|
||||
[Injectable]
|
||||
public class WeatherGenerator
|
||||
public class WeatherGenerator(
|
||||
TimeUtil _timeUtil,
|
||||
SeasonalEventService _seasonalEventService,
|
||||
WeatherHelper _weatherHelper,
|
||||
ConfigServer _configServer,
|
||||
WeightedRandomHelper _weightedRandomHelper,
|
||||
RandomUtil _randomUtil
|
||||
)
|
||||
{
|
||||
protected TimeUtil _timeUtil;
|
||||
protected SeasonalEventService _seasonalEventService;
|
||||
protected WeatherHelper _weatherHelper;
|
||||
protected ConfigServer _configServer;
|
||||
protected WeightedRandomHelper _weightedRandomHelper;
|
||||
protected RandomUtil _randomUtil;
|
||||
protected WeatherConfig _weatherConfig;
|
||||
|
||||
public WeatherGenerator(
|
||||
TimeUtil timeUtil,
|
||||
SeasonalEventService seasonalEventService,
|
||||
WeatherHelper weatherHelper,
|
||||
ConfigServer configServer,
|
||||
WeightedRandomHelper weightedRandomHelper,
|
||||
RandomUtil randomUtil
|
||||
)
|
||||
{
|
||||
_timeUtil = timeUtil;
|
||||
_seasonalEventService = seasonalEventService;
|
||||
_weatherHelper = weatherHelper;
|
||||
_configServer = configServer;
|
||||
_weightedRandomHelper = weightedRandomHelper;
|
||||
_randomUtil = randomUtil;
|
||||
|
||||
_weatherConfig = _configServer.GetConfig<WeatherConfig>();
|
||||
}
|
||||
protected WeatherConfig _weatherConfig = _configServer.GetConfig<WeatherConfig>();
|
||||
|
||||
/**
|
||||
* Get current + raid datetime and format into correct BSG format and return
|
||||
@@ -47,13 +29,13 @@ public class WeatherGenerator
|
||||
public void CalculateGameTime(WeatherData data)
|
||||
{
|
||||
var computedDate = DateTime.Now;
|
||||
var formattedDate = this._timeUtil.FormatDate(computedDate);
|
||||
var formattedDate = _timeUtil.FormatDate(computedDate);
|
||||
|
||||
data.Date = formattedDate;
|
||||
data.Time = GetBsgFormattedInRaidTime();
|
||||
data.Acceleration = this._weatherConfig.Acceleration;
|
||||
data.Acceleration = _weatherConfig.Acceleration;
|
||||
|
||||
data.Season = this._seasonalEventService.GetActiveWeatherSeason();
|
||||
data.Season = _seasonalEventService.GetActiveWeatherSeason();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,7 +46,7 @@ public class WeatherGenerator
|
||||
*/
|
||||
protected string GetBsgFormattedInRaidTime()
|
||||
{
|
||||
var clientAcceleratedDate = this._weatherHelper.GetInRaidTime();
|
||||
var clientAcceleratedDate = _weatherHelper.GetInRaidTime();
|
||||
|
||||
return GetBsgFormattedTime(clientAcceleratedDate);
|
||||
}
|
||||
@@ -121,10 +103,10 @@ public class WeatherGenerator
|
||||
|
||||
protected SeasonalValues GetWeatherValuesBySeason(Season currentSeason)
|
||||
{
|
||||
var result = this._weatherConfig.Weather.SeasonValues.TryGetValue(currentSeason.ToString(), out var value);
|
||||
var result = _weatherConfig.Weather.SeasonValues.TryGetValue(currentSeason.ToString(), out var value);
|
||||
if (!result)
|
||||
{
|
||||
return this._weatherConfig.Weather.SeasonValues["default"];
|
||||
return _weatherConfig.Weather.SeasonValues["default"];
|
||||
}
|
||||
|
||||
return value!;
|
||||
@@ -158,7 +140,7 @@ public class WeatherGenerator
|
||||
var normalTime = GetBsgFormattedTime(inRaidTime);
|
||||
var formattedDate = _timeUtil.FormatDate(timestamp.HasValue ? _timeUtil.GetDateTimeFromTimeStamp(timestamp.Value) : DateTime.UtcNow);
|
||||
var datetimeBsgFormat = $"{formattedDate} {normalTime}";
|
||||
|
||||
|
||||
weather.Timestamp = timestamp ?? _timeUtil.GetTimeStampFromEpoch(inRaidTime) / 1000; // matches weather.date
|
||||
weather.Date = formattedDate; // matches weather.timestamp
|
||||
weather.Time = datetimeBsgFormat; // matches weather.timestamp
|
||||
|
||||
Reference in New Issue
Block a user