Implement playerscavgenerator
This commit is contained in:
@@ -1,17 +1,77 @@
|
||||
using Core.Annotations;
|
||||
using Core.Helpers;
|
||||
using Core.Models.Eft.Common;
|
||||
using Core.Models.Eft.Common.Tables;
|
||||
using Core.Models.Enums;
|
||||
using Core.Models.Spt.Config;
|
||||
using Core.Servers;
|
||||
using Core.Services;
|
||||
using Core.Utils;
|
||||
using Core.Utils.Cloners;
|
||||
using ILogger = Core.Models.Utils.ILogger;
|
||||
|
||||
namespace Core.Generators;
|
||||
|
||||
[Injectable]
|
||||
public class PlayerScavGenerator
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly RandomUtil _randomUtil;
|
||||
private readonly DatabaseService _databaseService;
|
||||
private readonly HashUtil _hashUtil;
|
||||
private readonly ItemHelper _itemHelper;
|
||||
private readonly BotGeneratorHelper _botGeneratorHelper;
|
||||
private readonly SaveServer _saveServer;
|
||||
private readonly ProfileHelper _profileHelper;
|
||||
private readonly BotHelper _botHelper;
|
||||
private readonly FenceService _fenceService;
|
||||
private readonly BotLootCacheService _botLootCacheService;
|
||||
private readonly LocalisationService _localisationService;
|
||||
private readonly BotGenerator _botGenerator;
|
||||
private readonly ConfigServer _configServer;
|
||||
private readonly ICloner _cloner;
|
||||
private readonly TimeUtil _timeUtil;
|
||||
|
||||
private PlayerScavConfig _playerScavConfig;
|
||||
|
||||
public PlayerScavGenerator()
|
||||
public PlayerScavGenerator
|
||||
(
|
||||
ILogger 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>(ConfigTypes.PLAYERSCAV);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -21,7 +81,78 @@ public class PlayerScavGenerator
|
||||
/// <returns>profile object</returns>
|
||||
public PmcData Generate(string sessionID)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
// get karma level from profile
|
||||
var profile = _saveServer.GetProfile(sessionID);
|
||||
var profileCharactersClone = _cloner.Clone(profile.CharacterData);
|
||||
var pmcDataClone = _cloner.Clone(profileCharactersClone.PmcData);
|
||||
var existingScavDataClone = _cloner.Clone(profileCharactersClone.ScavData);
|
||||
|
||||
var scavKarmaLevel = GetScavKarmaLevel(pmcDataClone);
|
||||
|
||||
// use karma level to get correct karmaSettings
|
||||
var playerScavKarmaSettings = _playerScavConfig.KarmaLevel[scavKarmaLevel.ToString()];
|
||||
if (playerScavKarmaSettings == null)
|
||||
_logger.Error(_localisationService.GetText("scav-missing_karma_settings", scavKarmaLevel));
|
||||
|
||||
_logger.Debug($"generated player scav loadout with karma level {scavKarmaLevel}");
|
||||
|
||||
// Edit baseBotNode values
|
||||
var baseBotNode = ConstructBotBaseTemplate(playerScavKarmaSettings.BotTypeForLoot);
|
||||
AdjustBotTemplateWithKarmaSpecificSettings(playerScavKarmaSettings, baseBotNode);
|
||||
|
||||
var scavData = _botGenerator.GeneratePlayerScav(
|
||||
sessionID,
|
||||
playerScavKarmaSettings.BotTypeForLoot.ToLower(),
|
||||
"easy",
|
||||
baseBotNode,
|
||||
pmcDataClone);
|
||||
|
||||
// Remove cached bot data after scav was generated
|
||||
_botLootCacheService.ClearCache();
|
||||
|
||||
// Add scav metadata
|
||||
scavData.Savage = null;
|
||||
scavData.Aid = pmcDataClone.Aid;
|
||||
scavData.TradersInfo = pmcDataClone.TradersInfo;
|
||||
scavData.Info.Settings = new();
|
||||
scavData.Info.Bans = [];
|
||||
scavData.Info.RegistrationDate = pmcDataClone.Info.RegistrationDate;
|
||||
scavData.Info.GameVersion = pmcDataClone.Info.GameVersion;
|
||||
scavData.Info.MemberCategory = MemberCategory.UNIQUE_ID;
|
||||
scavData.Info.LockedMoveCommands = true;
|
||||
scavData.RagfairInfo = pmcDataClone.RagfairInfo;
|
||||
scavData.UnlockedInfo = pmcDataClone.UnlockedInfo;
|
||||
|
||||
// Persist previous scav data into new scav
|
||||
scavData.Id = existingScavDataClone.Id ?? pmcDataClone.Savage;
|
||||
scavData.SessionId = existingScavDataClone.SessionId ?? pmcDataClone.SessionId;
|
||||
scavData.Skills = this.GetScavSkills(existingScavDataClone);
|
||||
scavData.Stats = this.GetScavStats(existingScavDataClone);
|
||||
scavData.Info.Level = this.GetScavLevel(existingScavDataClone);
|
||||
scavData.Info.Experience = this.GetScavExperience(existingScavDataClone);
|
||||
scavData.Quests = existingScavDataClone.Quests ?? [];
|
||||
scavData.TaskConditionCounters = existingScavDataClone.TaskConditionCounters ?? new();
|
||||
scavData.Notes = existingScavDataClone.Notes ?? new() { DataNotes = new() };
|
||||
scavData.WishList = existingScavDataClone.WishList ?? new();
|
||||
scavData.Encyclopedia = pmcDataClone.Encyclopedia ?? new();
|
||||
|
||||
// Add additional items to player scav as loot
|
||||
AddAdditionalLootToPlayerScavContainers(playerScavKarmaSettings.LootItemsToAddChancePercent, scavData, [
|
||||
"TacticalVest",
|
||||
"Pockets",
|
||||
"Backpack"
|
||||
]);
|
||||
|
||||
// Remove secure container
|
||||
scavData = _profileHelper.RemoveSecureContainer(scavData);
|
||||
|
||||
// set cooldown timer
|
||||
scavData = SetScavCooldownTimer(scavData, pmcDataClone);
|
||||
|
||||
// add scav to profile
|
||||
_saveServer.GetProfile(sessionID).CharacterData.ScavData = scavData;
|
||||
|
||||
return scavData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -32,7 +163,40 @@ public class PlayerScavGenerator
|
||||
/// <param name="containersToAddTo">Possible slotIds to add loot to</param>
|
||||
protected void AddAdditionalLootToPlayerScavContainers(Dictionary<string, double> possibleItemsToAdd, BotBase scavData, List<string> containersToAddTo)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
foreach (var tpl in possibleItemsToAdd)
|
||||
{
|
||||
var shouldAdd = _randomUtil.GetChance100(tpl.Value);
|
||||
if (!shouldAdd)
|
||||
continue;
|
||||
|
||||
var itemResult = _itemHelper.GetItem(tpl.Key);
|
||||
if (!itemResult.Key)
|
||||
{
|
||||
_logger.Warning(_localisationService.GetText("scav-unable_to_add_item_to_player_scav", tpl));
|
||||
continue;
|
||||
}
|
||||
|
||||
var itemTemplate = itemResult.Value;
|
||||
var itemsToAdd = new List<Item>()
|
||||
{
|
||||
new Item()
|
||||
{
|
||||
Id = _hashUtil.Generate(),
|
||||
Template = itemTemplate.Id,
|
||||
Upd = _botGeneratorHelper.GenerateExtraPropertiesForItem(itemTemplate)
|
||||
}
|
||||
};
|
||||
|
||||
var result = _botGeneratorHelper.AddItemWithChildrenToEquipmentSlot(
|
||||
containersToAddTo,
|
||||
itemsToAdd[0].Id,
|
||||
itemTemplate.Id,
|
||||
itemsToAdd,
|
||||
scavData.Inventory);
|
||||
|
||||
if (result != ItemAddedResult.SUCCESS)
|
||||
_logger.Debug($"Unable to add keycard to bot. Reason: {result.ToString()}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -43,7 +207,19 @@ public class PlayerScavGenerator
|
||||
/// <returns>karma level</returns>
|
||||
protected double GetScavKarmaLevel(PmcData pmcData)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var fenceInfo = pmcData.TradersInfo[Traders.FENCE];
|
||||
|
||||
// can be empty during profile creation
|
||||
if (fenceInfo == null)
|
||||
{
|
||||
_logger.Warning(_localisationService.GetText("scav-missing_karma_level_getting_default"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fenceInfo.Standing > 6)
|
||||
return 6;
|
||||
|
||||
return Math.Floor(fenceInfo.Standing ?? 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -54,7 +230,19 @@ public class PlayerScavGenerator
|
||||
/// <returns>IBotType object</returns>
|
||||
protected BotType ConstructBotBaseTemplate(string botTypeForLoot)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var baseScavType = "assault";
|
||||
var asssaultBase = _cloner.Clone(_botHelper.GetBotTemplate(baseScavType));
|
||||
|
||||
// Loot bot is same as base bot, return base with no modification
|
||||
if (botTypeForLoot == baseScavType)
|
||||
return asssaultBase;
|
||||
|
||||
var lootBase = _cloner.Clone(_botHelper.GetBotTemplate(botTypeForLoot));
|
||||
asssaultBase.BotInventory = lootBase.BotInventory;
|
||||
asssaultBase.BotChances = lootBase.BotChances;
|
||||
asssaultBase.BotGeneration = lootBase.BotGeneration;
|
||||
|
||||
return asssaultBase;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -64,32 +252,90 @@ public class PlayerScavGenerator
|
||||
/// <param name="baseBotNode">bot template to modify according to karama level settings</param>
|
||||
protected void AdjustBotTemplateWithKarmaSpecificSettings(KarmaLevel karmaSettings, BotType baseBotNode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
// Adjust equipment chance values
|
||||
foreach (var equipment in karmaSettings.Modifiers.Equipment)
|
||||
{
|
||||
if (equipment.Value == 0)
|
||||
continue;
|
||||
|
||||
var prop = typeof(EquipmentChances).GetProperties().FirstOrDefault(p => p.Name == equipment.Key);
|
||||
var value = (int)prop.GetValue(baseBotNode.BotChances.EquipmentChances);
|
||||
var newValue = (int)value + karmaSettings.Modifiers.Equipment[equipment.Key];
|
||||
prop.SetValue(baseBotNode.BotChances.EquipmentChances, newValue);
|
||||
}
|
||||
|
||||
// Adjust mod chance values
|
||||
foreach (var mod in karmaSettings.Modifiers.Mod)
|
||||
{
|
||||
if (mod.Value == 0)
|
||||
continue;
|
||||
|
||||
baseBotNode.BotChances.WeaponModsChances[mod.Key] += karmaSettings.Modifiers.Mod[mod.Key];
|
||||
}
|
||||
|
||||
// Adjust item spawn quantity values
|
||||
var props = karmaSettings.ItemLimits.GetType().GetProperties();
|
||||
var botGenProps = baseBotNode.BotGeneration.Items.GetType().GetProperties();
|
||||
foreach (var prop in props)
|
||||
{
|
||||
botGenProps.FirstOrDefault(p => p.Name == prop.Name).SetValue(baseBotNode.BotGeneration.Items, prop.GetValue(karmaSettings.ItemLimits));
|
||||
}
|
||||
|
||||
// Blacklist equipment
|
||||
props = baseBotNode.BotInventory.Equipment.GetType().GetProperties();
|
||||
foreach (var equipment in karmaSettings.EquipmentBlacklist)
|
||||
{
|
||||
var blacklistedItemTpls = equipment.Value;
|
||||
foreach (var itemToRemove in blacklistedItemTpls)
|
||||
{
|
||||
var dict = (Dictionary<string, double>?)props.FirstOrDefault(p => p.Name == equipment.Key).GetValue(baseBotNode.BotInventory.Equipment);
|
||||
dict.Remove(itemToRemove);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Skills GetScavSkills(PmcData scavProfile)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
if (scavProfile?.Skills != null)
|
||||
return scavProfile.Skills;
|
||||
|
||||
return GetDefaultScavSkills();
|
||||
}
|
||||
|
||||
protected Skills GetDefaultScavSkills()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return new()
|
||||
{
|
||||
Common = new(new(), new()),
|
||||
Mastering = new(),
|
||||
Points = 0
|
||||
};
|
||||
}
|
||||
|
||||
protected Stats GetScavStats(PmcData scavProfile)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
if (scavProfile?.Stats != null)
|
||||
return scavProfile.Stats;
|
||||
|
||||
return _profileHelper.GetDefaultCounters();
|
||||
}
|
||||
|
||||
protected int GetScavLevel(PmcData scavProfile)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
// Info can be null on initial account creation
|
||||
if (scavProfile?.Info?.Level == null)
|
||||
return 1;
|
||||
|
||||
return scavProfile?.Info?.Level ?? 1;
|
||||
}
|
||||
|
||||
protected int GetScavExperience(PmcData scavProfile)
|
||||
protected double GetScavExperience(PmcData scavProfile)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
// Info can be null on initial account creation
|
||||
if (scavProfile?.Info?.Experience == null)
|
||||
return 0;
|
||||
|
||||
return scavProfile?.Info?.Experience ?? 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -101,6 +347,32 @@ public class PlayerScavGenerator
|
||||
/// <returns></returns>
|
||||
protected PmcData SetScavCooldownTimer(PmcData scavData, PmcData pmcData)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
// Set cooldown time.
|
||||
// Make sure to apply ScavCooldownTimer bonus from Hideout if the player has it.
|
||||
var scavLockDuration = _databaseService.GetGlobals().Configuration.SavagePlayCooldown;
|
||||
var modifier = 1D;
|
||||
|
||||
foreach (var bonus in pmcData.Bonuses)
|
||||
{
|
||||
if (bonus.Type == BonusType.ScavCooldownTimer)
|
||||
{
|
||||
// Value is negative, so add.
|
||||
// Also note that for scav cooldown, multiple bonuses stack additively.
|
||||
modifier += (bonus?.Value ?? 1) / 100;
|
||||
}
|
||||
}
|
||||
|
||||
var fenceInfo = _fenceService.GetFenceInfo(pmcData);
|
||||
modifier *= fenceInfo.SavageCooldownModifier ?? 1;
|
||||
scavLockDuration *= modifier;
|
||||
|
||||
var fullProfile = _profileHelper.GetFullProfile(pmcData?.SessionId);
|
||||
if (fullProfile?.ProfileInfo?.Edition.ToLower().StartsWith(AccountTypes.SPT_DEVELOPER) ?? false)
|
||||
scavLockDuration = 10;
|
||||
|
||||
if (scavData?.Info != null)
|
||||
scavData.Info.SavageLockTime = _timeUtil.GetTimeStamp() / 1000 + (long)scavLockDuration;
|
||||
|
||||
return scavData;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user