diff --git a/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/hideout.json b/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/hideout.json index 30f80bb87..9b42fcda0 100644 --- a/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/hideout.json +++ b/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/hideout.json @@ -5,7 +5,8 @@ "inRaid": 60, "outOfRaid": 10 }, - "expCraftAmount": 10, + "craftingExpAmount": 12.5, + "craftingExpForHoursOfCrafting": 3.75, "overrideCraftTimeSeconds": -1, "overrideBuildTimeSeconds": -1, "updateProfileHideoutWhenActiveWithinMinutes": 90, diff --git a/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/repair.json b/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/repair.json index bea9e5d05..83b46c3bf 100644 --- a/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/repair.json +++ b/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/repair.json @@ -1,17 +1,17 @@ { "priceMultiplier": 1, "applyRandomizeDurabilityLoss": true, - "armorKitSkillPointGainPerRepairPointMultiplier": 0.05, + "armorKitSkillPointGainPerRepairPointMultiplier": 0.1, "repairKitIntellectGainMultiplier": { - "weapon": 0.111, - "armor": 0.077 + "weapon": 0.1, + "armor": 0.1 }, "weaponTreatment": { "critSuccessChance": 0.1, "critSuccessAmount": 4, "critFailureChance": 0.1, "critFailureAmount": 4, - "pointGainMultiplier": 0.6 + "pointGainMultiplier": 0.2 }, "repairKit": { "armor": { diff --git a/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs b/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs index dcbeb709e..2a137c752 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs @@ -217,7 +217,8 @@ ItemEventRouterResponse output profileHelper.AddSkillPointsToPlayer( pmcData, SkillTypes.HideoutManagement, - globals.Configuration.SkillsSettings.HideoutManagement.SkillPointsPerAreaUpgrade + globals.Configuration.SkillsSettings.HideoutManagement.SkillPointsPerAreaUpgrade, + true ); } @@ -687,8 +688,9 @@ public ItemEventRouterResponse ScavCaseProductionStart(PmcData pmcData, HideoutS ); pmcData.Hideout.Production[request.RecipeId].SptIsScavCase = true; - // reward charisma based on skill progress rate for each scav production start + // reward charisma and hideout management based on skill progress rate for each scav production start profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.Charisma, 1, true); + profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.HideoutManagement, 1, true); return output; } @@ -822,7 +824,7 @@ ItemEventRouterResponse output } // Variables for management of skill - var craftingExpAmount = 0; + double craftingExpAmount = 0; var counterHoursCrafting = GetCustomSptHoursCraftingTaskConditionCounter(pmcData, recipe); var totalCraftingHours = counterHoursCrafting.Value; @@ -863,19 +865,19 @@ ItemEventRouterResponse output // Check if the recipe is the same as the last one - get bonus when crafting same thing multiple times var area = pmcData.Hideout.Areas.FirstOrDefault(area => area.Type == recipe.AreaType); if (area is not null && request.RecipeId != area.LastRecipe) - // 1 point per craft upon the end of production for alternating between 2 different crafting recipes in the same module + // 5 points per craft upon the end of production for alternating between 2 different crafting recipes in the same module { - craftingExpAmount += HideoutConfig.ExpCraftAmount; // Default is 10 + craftingExpAmount += HideoutConfig.CraftingExpAmount; // Default is 12.5, scaled (at 0.4 scale => 5 points per alternating craft) } // Update variable with time spent crafting item(s) - // 1 point per 8 hours of crafting + // 1.5 (3.75 w/ applying default 0.4 scale) points per 8 hours of crafting totalCraftingHours += recipe.ProductionTime; if (totalCraftingHours / HideoutConfig.HoursForSkillCrafting >= 1) { // Spent enough time crafting to get a bonus xp multiplier var multiplierCrafting = Math.Floor(totalCraftingHours.Value / HideoutConfig.HoursForSkillCrafting); - craftingExpAmount += (int)(1 * multiplierCrafting); + craftingExpAmount += (HideoutConfig.CraftingExpForHoursOfCrafting * multiplierCrafting); totalCraftingHours -= HideoutConfig.HoursForSkillCrafting * multiplierCrafting; } @@ -943,12 +945,18 @@ ItemEventRouterResponse output // Add Crafting skill to player profile if (craftingExpAmount > 0) { - profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.Crafting, craftingExpAmount); + profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.Crafting, craftingExpAmount, true); + // TODO: verify this is still giving intellect skill points on live var intellectAmountToGive = 0.5 * Math.Round((double)(craftingExpAmount / 15)); if (intellectAmountToGive > 0) { - profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.Intellect, intellectAmountToGive); + profileHelper.AddSkillPointsToPlayer( + pmcData, + SkillTypes.Intellect, + intellectAmountToGive, + useSkillProgressRateMultiplier: false + ); } } diff --git a/Libraries/SPTarkov.Server.Core/Controllers/InventoryController.cs b/Libraries/SPTarkov.Server.Core/Controllers/InventoryController.cs index 2bab4785b..eea35a1f1 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/InventoryController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/InventoryController.cs @@ -277,7 +277,13 @@ protected void FlagItemsAsInspectedAndRewardXp(IEnumerable itemTpls, Sp } // TODO: update this with correct calculation using values from globals json - profileHelper.AddSkillPointsToPlayer(fullProfile.CharacterData.PmcData, SkillTypes.Intellect, 0.05 * itemTpls.Count()); + // TODO: verify this is still giving intellect skill points on live + profileHelper.AddSkillPointsToPlayer( + fullProfile.CharacterData.PmcData, + SkillTypes.Intellect, + 0.05 * itemTpls.Count(), + useSkillProgressRateMultiplier: false + ); } /// diff --git a/Libraries/SPTarkov.Server.Core/Helpers/HideoutHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/HideoutHelper.cs index ce4080404..6595da798 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/HideoutHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/HideoutHelper.cs @@ -723,7 +723,7 @@ protected void UpdateFuel(BotHideoutArea generatorArea, PmcData pmcData, bool is // Fuel consumed / 10 is over 1, add hideout management skill point if (pmcData is not null && Math.Floor(pointsConsumed / 10) >= 1) { - profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.HideoutManagement, 1); + profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.HideoutManagement, 2, useSkillProgressRateMultiplier: true); pointsConsumed -= 10; } @@ -925,7 +925,7 @@ protected void UpdateWaterFilters(BotHideoutArea waterFilterArea, Production pro // Check units consumed for possible increment of hideout mgmt skill point if (pmcData is not null && Math.Floor(pointsConsumed / 10) >= 1) { - profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.HideoutManagement, 1); + profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.HideoutManagement, 2, useSkillProgressRateMultiplier: true); pointsConsumed -= 10; } @@ -1076,7 +1076,7 @@ protected void UpdateAirFilters(BotHideoutArea airFilterArea, PmcData pmcData, b // check unit consumed for increment skill point if (pmcData is not null && Math.Floor(pointsConsumed / 10) >= 1) { - profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.HideoutManagement, 1); + profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.HideoutManagement, 2, useSkillProgressRateMultiplier: true); pointsConsumed -= 10; } diff --git a/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs index a912c83f2..8a76862a2 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs @@ -195,7 +195,14 @@ private void AddPrestigeRewardsToProfile(MongoId sessionId, SptProfile newProfil case RewardType.Skill: if (Enum.TryParse(reward.Target, out SkillTypes result)) { - profileHelper.AddSkillPointsToPlayer(newProfile.CharacterData!.PmcData!, result, reward.Value.GetValueOrDefault(0)); + // skill reward values are always 100 (+1 level), so adjustment for low levels will give a wrong result + profileHelper.AddSkillPointsToPlayer( + newProfile.CharacterData!.PmcData!, + result, + reward.Value.GetValueOrDefault(0), + useSkillProgressRateMultiplier: false, + adjustSkillExpForLowLevels: false + ); } else { diff --git a/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs index 93ff6428a..ea1711810 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs @@ -461,7 +461,7 @@ public bool HasEliteSkillLevel(SkillTypes skill, PmcData pmcProfile) } /// - /// Add points to a specific skill in player profile + /// Add points to a specific skill in player profile, adjusted for low levels by default /// /// Player profile with skill /// Skill to add points to @@ -473,6 +473,25 @@ public void AddSkillPointsToPlayer( double pointsToAddToSkill, bool useSkillProgressRateMultiplier = false ) + { + AddSkillPointsToPlayer(pmcProfile, skill, pointsToAddToSkill, useSkillProgressRateMultiplier, true); + } + + /// + /// Add points to a specific skill in player profile + /// + /// Player profile with skill + /// Skill to add points to + /// Points to add + /// Skills are multiplied by a value in globals, default is off to maintain compatibility with legacy code + /// Skills are multiplied by a multiplier for lower levels; if false, treats every level as requiring 100 points + public void AddSkillPointsToPlayer( + PmcData pmcProfile, + SkillTypes skill, + double pointsToAddToSkill, + bool useSkillProgressRateMultiplier = false, + bool adjustSkillExpForLowLevels = true + ) { if (pointsToAddToSkill < 0D) { @@ -517,7 +536,9 @@ public void AddSkillPointsToPlayer( pointsToAddToSkill *= multiplier; } - var adjustedSkillProgress = AdjustSkillExpForLowLevels(profileSkill.Progress, pointsToAddToSkill); + var adjustedSkillProgress = adjustSkillExpForLowLevels + ? AdjustSkillExpForLowLevels(profileSkill.Progress, pointsToAddToSkill) + : pointsToAddToSkill; profileSkill.Progress += adjustedSkillProgress; profileSkill.Progress = Math.Min(profileSkill.Progress, 5100); // Prevent skill from ever going above level 51 (5100) diff --git a/Libraries/SPTarkov.Server.Core/Helpers/RewardHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/RewardHelper.cs index 9a7530bd1..0124a638d 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/RewardHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/RewardHelper.cs @@ -73,10 +73,13 @@ public List ApplyRewards( { case RewardType.Skill: // This needs to use the passed in profileData, as it could be the scav profile + // skill reward values are always 100 (+1 level), so adjustment for low levels will give a wrong result profileHelper.AddSkillPointsToPlayer( profileData, Enum.Parse(reward.Target), - reward.Value.GetValueOrDefault(0) + reward.Value.GetValueOrDefault(0), + useSkillProgressRateMultiplier: false, + adjustSkillExpForLowLevels: false ); break; case RewardType.Experience: diff --git a/Libraries/SPTarkov.Server.Core/Models/Spt/Config/HideoutConfig.cs b/Libraries/SPTarkov.Server.Core/Models/Spt/Config/HideoutConfig.cs index 1699cbe55..379d3e401 100644 --- a/Libraries/SPTarkov.Server.Core/Models/Spt/Config/HideoutConfig.cs +++ b/Libraries/SPTarkov.Server.Core/Models/Spt/Config/HideoutConfig.cs @@ -24,8 +24,14 @@ public record HideoutConfig : BaseConfig [JsonPropertyName("hoursForSkillCrafting")] public int HoursForSkillCrafting { get; set; } - [JsonPropertyName("expCraftAmount")] - public int ExpCraftAmount { get; set; } + [Obsolete("Will be removed in 4.1, use CraftingExpAmount")] + public int ExpCraftAmount { get; set; } = 0; + + [JsonPropertyName("craftingExpAmount")] + public double CraftingExpAmount { get; set; } + + [JsonPropertyName("craftingExpForHoursOfCrafting")] + public double CraftingExpForHoursOfCrafting { get; set; } [JsonPropertyName("overrideCraftTimeSeconds")] public int OverrideCraftTimeSeconds { get; set; } diff --git a/Libraries/SPTarkov.Server.Core/Services/RepairService.cs b/Libraries/SPTarkov.Server.Core/Services/RepairService.cs index edbc2cc9c..37164278f 100644 --- a/Libraries/SPTarkov.Server.Core/Services/RepairService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/RepairService.cs @@ -185,10 +185,12 @@ public void AddRepairSkillPoints(MongoId sessionId, RepairDetails repairDetails, ); } + // Every 10 points of repair gives 1 skill point scaled by skillProgressRate + // ArmorKitSkillPointGainPerRepairPointMultiplier is 0.1 var pointsToAddToVestSkill = repairDetails.RepairPoints * RepairConfig.ArmorKitSkillPointGainPerRepairPointMultiplier; logger.Debug($"Added: {pointsToAddToVestSkill} {vestSkillToLevel} skill"); - profileHelper.AddSkillPointsToPlayer(pmcData, vestSkillToLevel, pointsToAddToVestSkill.GetValueOrDefault(0)); + profileHelper.AddSkillPointsToPlayer(pmcData, vestSkillToLevel, pointsToAddToVestSkill.GetValueOrDefault(0), true); } // Handle trader repair - gives charisma based on (repair cost/10 * skill progress rate) @@ -245,18 +247,9 @@ protected double GetIntellectGainedFromRepair(RepairDetails repairDetails) protected double GetWeaponRepairSkillPoints(RepairDetails repairDetails) { var random = new Random(); - // This formula and associated configs is calculated based on 30 repairs done on live - // The points always came out 2-aligned, which is why there's a divide/multiply by 2 with ceil calls - var gainMult = RepairConfig.WeaponTreatment.PointGainMultiplier; - - // First we get a baseline based on our repair amount, and gain multiplier with a bit of rounding - var step1 = Math.Ceiling(repairDetails.RepairAmount.Value / 2) * gainMult; - - // Then we have to get the next even number - var step2 = Math.Ceiling(step1 / 2) * 2; - - // Then multiply by 2 again to hopefully get to what live would give us - var skillPoints = step2 * 2; + // Every 5 points repaired with kit should give 0.4 skill points, so PointGainMultiplier is 0.2 + // The return value is later scaled in AddSkillPointsToPlayer, i.e. 1 skill point returned here = 0.4 skill points added + var skillPoints = repairDetails.RepairAmount.GetValueOrDefault(0) * RepairConfig.WeaponTreatment.PointGainMultiplier; // You can both crit fail and succeed at the same time, for fun (Balances out to 0 with default settings) // Add a random chance to crit-fail