From d1f3dd79a786a488fa471bac1c6a8f506ad28905 Mon Sep 17 00:00:00 2001 From: rootdarkarchon Date: Fri, 13 Feb 2026 20:28:59 +0100 Subject: [PATCH 01/13] Adjust ArmorKitSkillPointGainPerRepairPointMultiplier evaluation --- Libraries/SPTarkov.Server.Assets/SPT_Data/configs/repair.json | 2 +- Libraries/SPTarkov.Server.Core/Services/RepairService.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/repair.json b/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/repair.json index bea9e5d05..4810f5d35 100644 --- a/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/repair.json +++ b/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/repair.json @@ -1,7 +1,7 @@ { "priceMultiplier": 1, "applyRandomizeDurabilityLoss": true, - "armorKitSkillPointGainPerRepairPointMultiplier": 0.05, + "armorKitSkillPointGainPerRepairPointMultiplier": 0.1, "repairKitIntellectGainMultiplier": { "weapon": 0.111, "armor": 0.077 diff --git a/Libraries/SPTarkov.Server.Core/Services/RepairService.cs b/Libraries/SPTarkov.Server.Core/Services/RepairService.cs index edbc2cc9c..51e9ee6e7 100644 --- a/Libraries/SPTarkov.Server.Core/Services/RepairService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/RepairService.cs @@ -188,7 +188,7 @@ public void AddRepairSkillPoints(MongoId sessionId, RepairDetails repairDetails, 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) From e57f3601fe94ad585711bab577b2ea1b5bd571e0 Mon Sep 17 00:00:00 2001 From: rootdarkarchon Date: Fri, 13 Feb 2026 20:39:27 +0100 Subject: [PATCH 02/13] Adjust GetWeaponRepairSkillPoints --- .../SPT_Data/configs/repair.json | 2 +- .../Services/RepairService.cs | 17 +++++------------ 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/repair.json b/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/repair.json index 4810f5d35..88286a91e 100644 --- a/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/repair.json +++ b/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/repair.json @@ -11,7 +11,7 @@ "critSuccessAmount": 4, "critFailureChance": 0.1, "critFailureAmount": 4, - "pointGainMultiplier": 0.6 + "pointGainMultiplier": 0.1 }, "repairKit": { "armor": { diff --git a/Libraries/SPTarkov.Server.Core/Services/RepairService.cs b/Libraries/SPTarkov.Server.Core/Services/RepairService.cs index 51e9ee6e7..287d015f6 100644 --- a/Libraries/SPTarkov.Server.Core/Services/RepairService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/RepairService.cs @@ -185,6 +185,8 @@ 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"); @@ -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 10 points repaired should give 0.4 skill points, so PointGainMultiplier is 0.1 + // 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 From 5beca6eb8f128760c1295d2f9bb32e5792f2b1f2 Mon Sep 17 00:00:00 2001 From: rootdarkarchon Date: Fri, 13 Feb 2026 20:44:10 +0100 Subject: [PATCH 03/13] adjust WeaponRepair Treatment gain values and intellect gain values --- .../SPTarkov.Server.Assets/SPT_Data/configs/repair.json | 6 +++--- Libraries/SPTarkov.Server.Core/Services/RepairService.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/repair.json b/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/repair.json index 88286a91e..83b46c3bf 100644 --- a/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/repair.json +++ b/Libraries/SPTarkov.Server.Assets/SPT_Data/configs/repair.json @@ -3,15 +3,15 @@ "applyRandomizeDurabilityLoss": true, "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.1 + "pointGainMultiplier": 0.2 }, "repairKit": { "armor": { diff --git a/Libraries/SPTarkov.Server.Core/Services/RepairService.cs b/Libraries/SPTarkov.Server.Core/Services/RepairService.cs index 287d015f6..9ad2831bf 100644 --- a/Libraries/SPTarkov.Server.Core/Services/RepairService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/RepairService.cs @@ -247,7 +247,7 @@ protected double GetIntellectGainedFromRepair(RepairDetails repairDetails) protected double GetWeaponRepairSkillPoints(RepairDetails repairDetails) { var random = new Random(); - // Every 10 points repaired should give 0.4 skill points, so PointGainMultiplier is 0.1 + // Every 5 points repaired with kit should give 0.4 skill points, so PointGainMultiplier is 0.1 // 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; From 523c47bf47d1b15d1a692a768b65435eb790f356 Mon Sep 17 00:00:00 2001 From: rootdarkarchon Date: Fri, 13 Feb 2026 20:45:05 +0100 Subject: [PATCH 04/13] enable scaling for hideout upgrade --- .../SPTarkov.Server.Core/Controllers/HideoutController.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs b/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs index dcbeb709e..a5af36d81 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 ); } From 8f4235d4d82e57e94954aac994de9d1459ad7b1e Mon Sep 17 00:00:00 2001 From: rootdarkarchon Date: Fri, 13 Feb 2026 21:22:09 +0100 Subject: [PATCH 05/13] Adjust HandleRecipe --- .../SPT_Data/configs/hideout.json | 3 ++- .../Controllers/HideoutController.cs | 10 +++++----- .../Models/Spt/Config/HideoutConfig.cs | 10 ++++++++-- 3 files changed, 15 insertions(+), 8 deletions(-) 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.Core/Controllers/HideoutController.cs b/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs index a5af36d81..79a56ed41 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs @@ -823,7 +823,7 @@ ItemEventRouterResponse output } // Variables for management of skill - var craftingExpAmount = 0; + double craftingExpAmount = 0; var counterHoursCrafting = GetCustomSptHoursCraftingTaskConditionCounter(pmcData, recipe); var totalCraftingHours = counterHoursCrafting.Value; @@ -866,17 +866,17 @@ ItemEventRouterResponse output 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 { - 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; } @@ -944,7 +944,7 @@ ItemEventRouterResponse output // Add Crafting skill to player profile if (craftingExpAmount > 0) { - profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.Crafting, craftingExpAmount); + profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.Crafting, craftingExpAmount, true); var intellectAmountToGive = 0.5 * Math.Round((double)(craftingExpAmount / 15)); if (intellectAmountToGive > 0) 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; } From 9cd3bd40389517d01008f1dcf2de2b5fbc9ca459 Mon Sep 17 00:00:00 2001 From: rootdarkarchon Date: Fri, 13 Feb 2026 21:37:17 +0100 Subject: [PATCH 06/13] adjust skill points addition for PrestigeHelper and RewardHelper --- Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs | 2 +- Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs | 6 ++++-- Libraries/SPTarkov.Server.Core/Helpers/RewardHelper.cs | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs index a912c83f2..8f5fdfc3c 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs @@ -195,7 +195,7 @@ 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)); + profileHelper.AddSkillPointsToPlayer(newProfile.CharacterData!.PmcData!, result, reward.Value.GetValueOrDefault(0), adjustSkillExpForLowLevels: false); } else { diff --git a/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs index 93ff6428a..3ce81b3be 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs @@ -467,11 +467,13 @@ public bool HasEliteSkillLevel(SkillTypes skill, PmcData pmcProfile) /// 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 useSkillProgressRateMultiplier = false, + bool adjustSkillExpForLowLevels = true ) { if (pointsToAddToSkill < 0D) @@ -517,7 +519,7 @@ 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..44355005e 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/RewardHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/RewardHelper.cs @@ -76,7 +76,8 @@ public List ApplyRewards( profileHelper.AddSkillPointsToPlayer( profileData, Enum.Parse(reward.Target), - reward.Value.GetValueOrDefault(0) + reward.Value.GetValueOrDefault(0), + adjustSkillExpForLowLevels: false ); break; case RewardType.Experience: From cd127c872db912fb8d620be66625176e4d11d5c2 Mon Sep 17 00:00:00 2001 From: rootdarkarchon Date: Fri, 13 Feb 2026 21:37:32 +0100 Subject: [PATCH 07/13] format --- Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs | 7 ++++++- Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs index 8f5fdfc3c..534bb580f 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs @@ -195,7 +195,12 @@ 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), adjustSkillExpForLowLevels: false); + profileHelper.AddSkillPointsToPlayer( + newProfile.CharacterData!.PmcData!, + result, + reward.Value.GetValueOrDefault(0), + adjustSkillExpForLowLevels: false + ); } else { diff --git a/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs index 3ce81b3be..51081433d 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs @@ -519,7 +519,9 @@ public void AddSkillPointsToPlayer( pointsToAddToSkill *= multiplier; } - var adjustedSkillProgress = adjustSkillExpForLowLevels ? AdjustSkillExpForLowLevels(profileSkill.Progress, pointsToAddToSkill) : 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) From 1d198842bfec7a55938627c02cd445f1c580b7fd Mon Sep 17 00:00:00 2001 From: rootdarkarchon Date: Fri, 13 Feb 2026 21:40:40 +0100 Subject: [PATCH 08/13] adjust doc --- Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs | 1 + Libraries/SPTarkov.Server.Core/Helpers/RewardHelper.cs | 1 + Libraries/SPTarkov.Server.Core/Services/RepairService.cs | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs index 534bb580f..16ec355b5 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs @@ -195,6 +195,7 @@ private void AddPrestigeRewardsToProfile(MongoId sessionId, SptProfile newProfil case RewardType.Skill: if (Enum.TryParse(reward.Target, out SkillTypes result)) { + // skill reward values are always 100 (+1 level), so adjustment for low levels will give a wrong result profileHelper.AddSkillPointsToPlayer( newProfile.CharacterData!.PmcData!, result, diff --git a/Libraries/SPTarkov.Server.Core/Helpers/RewardHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/RewardHelper.cs index 44355005e..327640b84 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/RewardHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/RewardHelper.cs @@ -73,6 +73,7 @@ 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), diff --git a/Libraries/SPTarkov.Server.Core/Services/RepairService.cs b/Libraries/SPTarkov.Server.Core/Services/RepairService.cs index 9ad2831bf..37164278f 100644 --- a/Libraries/SPTarkov.Server.Core/Services/RepairService.cs +++ b/Libraries/SPTarkov.Server.Core/Services/RepairService.cs @@ -247,7 +247,7 @@ protected double GetIntellectGainedFromRepair(RepairDetails repairDetails) protected double GetWeaponRepairSkillPoints(RepairDetails repairDetails) { var random = new Random(); - // Every 5 points repaired with kit should give 0.4 skill points, so PointGainMultiplier is 0.1 + // 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; From 5d455c6609bfcc7e78b1e62e003277ebce43bf2d Mon Sep 17 00:00:00 2001 From: rootdarkarchon Date: Fri, 13 Feb 2026 21:47:32 +0100 Subject: [PATCH 09/13] adjust doc --- .../SPTarkov.Server.Core/Controllers/HideoutController.cs | 3 ++- .../SPTarkov.Server.Core/Controllers/InventoryController.cs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs b/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs index 79a56ed41..18d162ca0 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs @@ -864,7 +864,7 @@ 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.CraftingExpAmount; // Default is 12.5, scaled (at 0.4 scale => 5 points per alternating craft) } @@ -946,6 +946,7 @@ ItemEventRouterResponse output { 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) { diff --git a/Libraries/SPTarkov.Server.Core/Controllers/InventoryController.cs b/Libraries/SPTarkov.Server.Core/Controllers/InventoryController.cs index 2bab4785b..531b7d909 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/InventoryController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/InventoryController.cs @@ -277,6 +277,7 @@ protected void FlagItemsAsInspectedAndRewardXp(IEnumerable itemTpls, Sp } // TODO: update this with correct calculation using values from globals json + // TODO: verify this is still giving intellect skill points on live profileHelper.AddSkillPointsToPlayer(fullProfile.CharacterData.PmcData, SkillTypes.Intellect, 0.05 * itemTpls.Count()); } From c296912bc60f1187ac0a413d0f86fe725f277c2a Mon Sep 17 00:00:00 2001 From: rootdarkarchon Date: Fri, 13 Feb 2026 22:00:14 +0100 Subject: [PATCH 10/13] amend some ABI changes --- .../Controllers/HideoutController.cs | 7 ++++++- .../Controllers/InventoryController.cs | 7 ++++++- .../Helpers/HideoutHelper.cs | 6 +++--- .../Helpers/ProfileHelper.cs | 17 +++++++++++++++++ 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs b/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs index 18d162ca0..a2e148738 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs @@ -950,7 +950,12 @@ ItemEventRouterResponse output 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 531b7d909..eea35a1f1 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/InventoryController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/InventoryController.cs @@ -278,7 +278,12 @@ protected void FlagItemsAsInspectedAndRewardXp(IEnumerable itemTpls, Sp // TODO: update this with correct calculation using values from globals json // TODO: verify this is still giving intellect skill points on live - profileHelper.AddSkillPointsToPlayer(fullProfile.CharacterData.PmcData, SkillTypes.Intellect, 0.05 * itemTpls.Count()); + 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..473881302 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, 1, useSkillProgressRateMultiplier: false); 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, 1, useSkillProgressRateMultiplier: false); 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, 1, useSkillProgressRateMultiplier: false); pointsConsumed -= 10; } diff --git a/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs index 51081433d..ea1711810 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/ProfileHelper.cs @@ -460,6 +460,23 @@ public bool HasEliteSkillLevel(SkillTypes skill, PmcData pmcProfile) return profileSkill.Progress >= 5100; // 51 } + /// + /// Add points to a specific skill in player profile, adjusted for low levels by default + /// + /// 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 + public void AddSkillPointsToPlayer( + PmcData pmcProfile, + SkillTypes skill, + double pointsToAddToSkill, + bool useSkillProgressRateMultiplier = false + ) + { + AddSkillPointsToPlayer(pmcProfile, skill, pointsToAddToSkill, useSkillProgressRateMultiplier, true); + } + /// /// Add points to a specific skill in player profile /// From a3e3c18fc927400c04305f529bf1f595df25f4b7 Mon Sep 17 00:00:00 2001 From: rootdarkarchon Date: Fri, 13 Feb 2026 22:03:42 +0100 Subject: [PATCH 11/13] clarify bool usage --- Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs | 1 + Libraries/SPTarkov.Server.Core/Helpers/RewardHelper.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs index 16ec355b5..8a76862a2 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/PrestigeHelper.cs @@ -200,6 +200,7 @@ private void AddPrestigeRewardsToProfile(MongoId sessionId, SptProfile newProfil newProfile.CharacterData!.PmcData!, result, reward.Value.GetValueOrDefault(0), + useSkillProgressRateMultiplier: false, adjustSkillExpForLowLevels: false ); } diff --git a/Libraries/SPTarkov.Server.Core/Helpers/RewardHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/RewardHelper.cs index 327640b84..0124a638d 100644 --- a/Libraries/SPTarkov.Server.Core/Helpers/RewardHelper.cs +++ b/Libraries/SPTarkov.Server.Core/Helpers/RewardHelper.cs @@ -78,6 +78,7 @@ public List ApplyRewards( profileData, Enum.Parse(reward.Target), reward.Value.GetValueOrDefault(0), + useSkillProgressRateMultiplier: false, adjustSkillExpForLowLevels: false ); break; From 278fa52e014a68b8708b2d2f2eff58f32480489f Mon Sep 17 00:00:00 2001 From: rootdarkarchon Date: Sat, 14 Feb 2026 10:43:47 +0100 Subject: [PATCH 12/13] adjust UpdateFuel, WaterFilters and AirFilters --- Libraries/SPTarkov.Server.Core/Helpers/HideoutHelper.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Libraries/SPTarkov.Server.Core/Helpers/HideoutHelper.cs b/Libraries/SPTarkov.Server.Core/Helpers/HideoutHelper.cs index 473881302..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, useSkillProgressRateMultiplier: false); + 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, useSkillProgressRateMultiplier: false); + 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, useSkillProgressRateMultiplier: false); + profileHelper.AddSkillPointsToPlayer(pmcData, SkillTypes.HideoutManagement, 2, useSkillProgressRateMultiplier: true); pointsConsumed -= 10; } From 4def3be6a83e34b81ebc3f87f3779d10c8756615 Mon Sep 17 00:00:00 2001 From: rootdarkarchon Date: Sat, 14 Feb 2026 10:57:29 +0100 Subject: [PATCH 13/13] add HideoutManagement skill progression to scav case --- .../SPTarkov.Server.Core/Controllers/HideoutController.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs b/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs index a2e148738..2a137c752 100644 --- a/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs +++ b/Libraries/SPTarkov.Server.Core/Controllers/HideoutController.cs @@ -688,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; }