Fix post-raid health (#661)

* Fix post-raid health
- Re-add death penalty for limbs
- Correctly set body part HP to 1 for cursed death only
- Use the server profile body part max HP for calculating penalties
- Never modify the body part max HP on the profile
- Remove ResetMaxLimbHp as it's unnecessary if we never update max HP elsewhere

* Formatting

* Remove unnecessary null coalescing

* Stupid formatting

---------

Co-authored-by: DrakiaXYZ <565558+TheDgtl@users.noreply.github.com>
This commit is contained in:
DrakiaXYZ
2025-10-26 01:47:40 -07:00
committed by GitHub
parent a524dc47dd
commit d375879a3a
5 changed files with 28 additions and 31 deletions
@@ -1,6 +1,7 @@
{
"healthMultipliers": {
"blacked": 0.1
"blacked": 0.1,
"death": 0.3
},
"save": {
"health": true
@@ -254,19 +254,6 @@ public static class ProfileExtensions
return quest?.Status ?? QuestStatusEnum.Locked;
}
/// <summary>
/// Use values from the profiles template to reset all body part max values
/// </summary>
/// <param name="profile">Profile to update</param>
/// <param name="profileTemplate">Template used to create profile</param>
public static void ResetMaxLimbHp(this PmcData profile, TemplateSide profileTemplate)
{
foreach (var (partKey, bodyPart) in profile.Health.BodyParts)
{
bodyPart.Health.Maximum = profileTemplate.Character.Health.BodyParts[partKey].Health.Maximum;
}
}
/// <summary>
/// Handle Remove event
/// Remove item from player inventory + insured items array
@@ -3,6 +3,7 @@ using SPTarkov.Server.Core.Exceptions.Helpers;
using SPTarkov.Server.Core.Models.Common;
using SPTarkov.Server.Core.Models.Eft.Common;
using SPTarkov.Server.Core.Models.Eft.Common.Tables;
using SPTarkov.Server.Core.Models.Eft.Health;
using SPTarkov.Server.Core.Models.Spt.Config;
using SPTarkov.Server.Core.Models.Utils;
using SPTarkov.Server.Core.Servers;
@@ -23,7 +24,7 @@ public class HealthHelper(ISptLogger<HealthHelper> logger, TimeUtil timeUtil, Co
/// <param name="sessionId">Session id</param>
/// <param name="pmcProfileToUpdate">Player profile to apply changes to</param>
/// <param name="healthChanges">Changes to apply </param>
public void ApplyHealthChangesToProfile(MongoId sessionId, PmcData pmcProfileToUpdate, BotBaseHealth healthChanges)
public void ApplyHealthChangesToProfile(MongoId sessionId, PmcData pmcProfileToUpdate, BotBaseHealth healthChanges, bool isDead)
{
/* TODO: Not used here, need to check node or a live profile, commented out for now to avoid the potential alloc - Cj
var fullProfile = saveServer.GetProfile(sessionId);
@@ -44,7 +45,7 @@ public class HealthHelper(ISptLogger<HealthHelper> logger, TimeUtil timeUtil, Co
var playerWasCursed = !PlayerHadGearOnRaidStart(pmcProfileToUpdate.Inventory);
// Alter saved profiles Health with values from post-raid client data
ModifyProfileHealthProperties(pmcProfileToUpdate, healthChanges.BodyParts, EffectsToSkip, playerWasCursed);
ModifyProfileHealthProperties(pmcProfileToUpdate, healthChanges.BodyParts, EffectsToSkip, isDead, playerWasCursed);
// Adjust hydration/energy/temperature
AdjustProfileHydrationEnergyTemperature(pmcProfileToUpdate, healthChanges);
@@ -103,11 +104,13 @@ public class HealthHelper(ISptLogger<HealthHelper> logger, TimeUtil timeUtil, Co
/// <param name="profileToAdjust">Player profile on server</param>
/// <param name="bodyPartChanges">Changes to apply</param>
/// <param name="effectsToSkip"></param>
/// <param name="isDead"></param>
/// <param name="playerWasCursed">Did player enter raid with no equipment</param>
protected void ModifyProfileHealthProperties(
PmcData profileToAdjust,
Dictionary<string, BodyPartHealth> bodyPartChanges,
HashSet<string>? effectsToSkip = null,
bool isDead = false,
bool playerWasCursed = false
)
{
@@ -131,17 +134,24 @@ public class HealthHelper(ISptLogger<HealthHelper> logger, TimeUtil timeUtil, Co
if (HealthConfig.Save.Health)
{
// Apply hp changes to profile
matchingProfilePart.Health.Current =
partProperties.Health.Current == 0
? partProperties.Health.Maximum * HealthConfig.HealthMultipliers.Blacked
: partProperties.Health.Current;
matchingProfilePart.Health.Maximum = partProperties.Health.Maximum;
// Cursed player + limb was not lost, reset to 20%
if (playerWasCursed && matchingProfilePart.Health.Current > 20)
if (!isDead)
{
matchingProfilePart.Health.Current = 20;
// If the player isn't dead, restore blacked limbs with a penalty
matchingProfilePart.Health.Current =
partProperties.Health.Current == 0
? matchingProfilePart.Health.Maximum * HealthConfig.HealthMultipliers.Blacked
: partProperties.Health.Current;
}
else
{
// If the player died, set all limbs with a penalty
matchingProfilePart.Health.Current = matchingProfilePart.Health.Maximum * HealthConfig.HealthMultipliers.Death;
// Cursed player, body part gets set to 1 on death
if (playerWasCursed)
{
matchingProfilePart.Health.Current = 1;
}
}
}
@@ -18,6 +18,9 @@ public record HealthMultipliers
{
[JsonPropertyName("blacked")]
public double Blacked { get; set; }
[JsonPropertyName("death")]
public double Death { get; set; }
}
public record HealthSave
@@ -792,11 +792,7 @@ public class LocationLifecycleService(
MergePmcAndScavEncyclopedias(serverPmcProfile, scavProfile);
// Handle temp, hydration, limb hp/effects
healthHelper.ApplyHealthChangesToProfile(sessionId, serverPmcProfile, postRaidProfile.Health);
// Required when player loses limb in-raid and fixes it, max now stuck at 50% or less if lost multiple times
var profileTemplate = profileHelper.GetProfileTemplateForSide(fullServerProfile.ProfileInfo.Edition, serverPmcProfile.Info.Side);
serverPmcProfile.ResetMaxLimbHp(profileTemplate);
healthHelper.ApplyHealthChangesToProfile(sessionId, serverPmcProfile, postRaidProfile.Health, isDead);
if (isTransfer)
{