Merge remote-tracking branch 'upstream/dev' into develop
This commit is contained in:
+44
-5
@@ -27,6 +27,14 @@ namespace Barotrauma
|
||||
get { return _strength; }
|
||||
set
|
||||
{
|
||||
if (!MathUtils.IsValid(value))
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError($"Attempted to set an affliction to an invalid strength ({value})\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (_nonClampedStrength < 0 && value > 0)
|
||||
{
|
||||
_nonClampedStrength = value;
|
||||
@@ -53,6 +61,9 @@ namespace Barotrauma
|
||||
[Serialize(true, IsPropertySaveable.Yes, description: "Explosion damage is applied per each affected limb. Should this affliction damage be divided by the count of affected limbs (1-15) or applied in full? Default: true. Only affects explosions."), Editable]
|
||||
public bool DivideByLimbCount { get; set; }
|
||||
|
||||
[Serialize(false, IsPropertySaveable.Yes, description: "Is the damage relative to the max vitality (percentage) or absolute (normal)"), Editable]
|
||||
public bool MultiplyByMaxVitality { get; private set; }
|
||||
|
||||
public float DamagePerSecond;
|
||||
public float DamagePerSecondTimer;
|
||||
public float PreviousVitalityDecrease;
|
||||
@@ -71,6 +82,13 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public Character Source;
|
||||
|
||||
private readonly static LocalizedString[] strengthTexts = new LocalizedString[]
|
||||
{
|
||||
TextManager.Get("AfflictionStrengthLow"),
|
||||
TextManager.Get("AfflictionStrengthMedium"),
|
||||
TextManager.Get("AfflictionStrengthHigh")
|
||||
};
|
||||
|
||||
public Affliction(AfflictionPrefab prefab, float strength)
|
||||
{
|
||||
#if CLIENT
|
||||
@@ -89,6 +107,16 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy properties here instead of using SerializableProperties (with reflection).
|
||||
/// </summary>
|
||||
public void CopyProperties(Affliction source)
|
||||
{
|
||||
Probability = source.Probability;
|
||||
DivideByLimbCount = source.DivideByLimbCount;
|
||||
MultiplyByMaxVitality = source.MultiplyByMaxVitality;
|
||||
}
|
||||
|
||||
public void Serialize(XElement element)
|
||||
{
|
||||
SerializableProperty.SerializeProperties(this, element);
|
||||
@@ -99,15 +127,26 @@ namespace Barotrauma
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
|
||||
}
|
||||
|
||||
public Affliction CreateMultiplied(float multiplier, float probability)
|
||||
public Affliction CreateMultiplied(float multiplier, Affliction affliction)
|
||||
{
|
||||
var instance = Prefab.Instantiate(NonClampedStrength * multiplier, Source);
|
||||
instance.Probability = probability;
|
||||
instance.CopyProperties(affliction);
|
||||
return instance;
|
||||
}
|
||||
|
||||
public override string ToString() => Prefab == null ? "Affliction (Invalid)" : $"Affliction ({Prefab.Name})";
|
||||
|
||||
public LocalizedString GetStrengthText()
|
||||
{
|
||||
return GetStrengthText(Strength, Prefab.MaxStrength);
|
||||
}
|
||||
|
||||
public static LocalizedString GetStrengthText(float strength, float maxStrength)
|
||||
{
|
||||
return strengthTexts[
|
||||
MathHelper.Clamp((int)Math.Floor(strength / maxStrength * strengthTexts.Length), 0, strengthTexts.Length - 1)];
|
||||
}
|
||||
|
||||
public AfflictionPrefab.Effect GetActiveEffect() => Prefab.GetActiveEffect(Strength);
|
||||
|
||||
public float GetVitalityDecrease(CharacterHealth characterHealth)
|
||||
@@ -424,15 +463,15 @@ namespace Barotrauma
|
||||
{
|
||||
statusEffect.Apply(type, deltaTime, characterHealth.Character, targetLimb);
|
||||
}
|
||||
if (targetLimb != null && statusEffect.HasTargetType(StatusEffect.TargetType.AllLimbs))
|
||||
if (characterHealth?.Character?.AnimController?.Limbs != null && statusEffect.HasTargetType(StatusEffect.TargetType.AllLimbs))
|
||||
{
|
||||
statusEffect.Apply(type, deltaTime, targetLimb.character, targets: targetLimb.character.AnimController.Limbs);
|
||||
statusEffect.Apply(type, deltaTime, characterHealth.Character, targets: characterHealth.Character.AnimController.Limbs);
|
||||
}
|
||||
if (statusEffect.HasTargetType(StatusEffect.TargetType.NearbyItems) ||
|
||||
statusEffect.HasTargetType(StatusEffect.TargetType.NearbyCharacters))
|
||||
{
|
||||
targets.Clear();
|
||||
targets.AddRange(statusEffect.GetNearbyTargets(characterHealth.Character.WorldPosition, targets));
|
||||
statusEffect.AddNearbyTargets(characterHealth.Character.WorldPosition, targets);
|
||||
statusEffect.Apply(type, deltaTime, characterHealth.Character, targets);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -10,7 +10,8 @@
|
||||
public override void Update(CharacterHealth characterHealth, Limb targetLimb, float deltaTime)
|
||||
{
|
||||
base.Update(characterHealth, targetLimb, deltaTime);
|
||||
characterHealth.BloodlossAmount += Strength * (1.0f / 60.0f) * deltaTime;
|
||||
float bloodlossResistance = GetResistance(characterHealth.BloodlossAffliction.Identifier);
|
||||
characterHealth.BloodlossAmount += Strength * (1.0f - bloodlossResistance) / 60.0f * deltaTime;
|
||||
if (Source != null)
|
||||
{
|
||||
characterHealth.BloodlossAffliction.Source = Source;
|
||||
|
||||
+43
-35
@@ -406,45 +406,53 @@ namespace Barotrauma
|
||||
|
||||
var root = doc.Root.FromPackage(pathToAppendage.ContentPackage);
|
||||
var limbElements = root.GetChildElements("limb").ToDictionary(e => e.GetAttributeString("id", null), e => e);
|
||||
//the IDs may need to be offset if the character has other extra appendages (e.g. from gene splicing)
|
||||
//that take up the IDs of this appendage
|
||||
int idOffset = 0;
|
||||
foreach (var jointElement in root.GetChildElements("joint"))
|
||||
{
|
||||
if (limbElements.TryGetValue(jointElement.GetAttributeString("limb2", null), out ContentXElement limbElement))
|
||||
if (!limbElements.TryGetValue(jointElement.GetAttributeString("limb2", null), out ContentXElement limbElement)) { continue; }
|
||||
|
||||
var jointParams = new RagdollParams.JointParams(jointElement, ragdoll.RagdollParams);
|
||||
Limb attachLimb = null;
|
||||
if (matchingAffliction.AttachLimbId > -1)
|
||||
{
|
||||
var jointParams = new RagdollParams.JointParams(jointElement, ragdoll.RagdollParams);
|
||||
Limb attachLimb = null;
|
||||
if (matchingAffliction.AttachLimbId > -1)
|
||||
{
|
||||
attachLimb = ragdoll.Limbs.FirstOrDefault(l => !l.IsSevered && l.Params.ID == matchingAffliction.AttachLimbId);
|
||||
}
|
||||
else if (matchingAffliction.AttachLimbName != null)
|
||||
{
|
||||
attachLimb = ragdoll.Limbs.FirstOrDefault(l => !l.IsSevered && l.Name == matchingAffliction.AttachLimbName);
|
||||
}
|
||||
else if (matchingAffliction.AttachLimbType != LimbType.None)
|
||||
{
|
||||
attachLimb = ragdoll.Limbs.FirstOrDefault(l => !l.IsSevered && l.type == matchingAffliction.AttachLimbType);
|
||||
}
|
||||
if (attachLimb == null)
|
||||
{
|
||||
attachLimb = ragdoll.Limbs.FirstOrDefault(l => !l.IsSevered && l.Params.ID == jointParams.Limb1);
|
||||
}
|
||||
if (attachLimb != null)
|
||||
{
|
||||
jointParams.Limb1 = attachLimb.Params.ID;
|
||||
var appendageLimbParams = new RagdollParams.LimbParams(limbElement, ragdoll.RagdollParams)
|
||||
{
|
||||
// Ensure that we have a valid id for the new limb
|
||||
ID = ragdoll.Limbs.Length
|
||||
};
|
||||
jointParams.Limb2 = appendageLimbParams.ID;
|
||||
Limb huskAppendage = new Limb(ragdoll, character, appendageLimbParams);
|
||||
huskAppendage.body.Submarine = character.Submarine;
|
||||
huskAppendage.body.SetTransform(attachLimb.SimPosition, attachLimb.Rotation);
|
||||
ragdoll.AddLimb(huskAppendage);
|
||||
ragdoll.AddJoint(jointParams);
|
||||
appendage.Add(huskAppendage);
|
||||
}
|
||||
attachLimb = ragdoll.Limbs.FirstOrDefault(l => !l.IsSevered && l.Params.ID == matchingAffliction.AttachLimbId);
|
||||
}
|
||||
else if (matchingAffliction.AttachLimbName != null)
|
||||
{
|
||||
attachLimb = ragdoll.Limbs.FirstOrDefault(l => !l.IsSevered && l.Name == matchingAffliction.AttachLimbName);
|
||||
}
|
||||
else if (matchingAffliction.AttachLimbType != LimbType.None)
|
||||
{
|
||||
attachLimb = ragdoll.Limbs.FirstOrDefault(l => !l.IsSevered && l.type == matchingAffliction.AttachLimbType);
|
||||
}
|
||||
if (attachLimb == null)
|
||||
{
|
||||
attachLimb = ragdoll.Limbs.FirstOrDefault(l => !l.IsSevered && l.Params.ID == jointParams.Limb1);
|
||||
}
|
||||
if (attachLimb != null)
|
||||
{
|
||||
jointParams.Limb1 = attachLimb.Params.ID;
|
||||
//the joint attaches to a limb outside the character's normal limb count = to another part of the appendage
|
||||
// -> if the appendage's IDs have been offset, we need to take that into account to attach to the correct limb
|
||||
if (jointParams.Limb1 >= ragdoll.RagdollParams.Limbs.Count)
|
||||
{
|
||||
jointParams.Limb1 += idOffset;
|
||||
}
|
||||
var appendageLimbParams = new RagdollParams.LimbParams(limbElement, ragdoll.RagdollParams);
|
||||
if (idOffset == 0)
|
||||
{
|
||||
idOffset = ragdoll.Limbs.Length - appendageLimbParams.ID;
|
||||
}
|
||||
jointParams.Limb2 = appendageLimbParams.ID = ragdoll.Limbs.Length;
|
||||
Limb huskAppendage = new Limb(ragdoll, character, appendageLimbParams);
|
||||
huskAppendage.body.Submarine = character.Submarine;
|
||||
huskAppendage.body.SetTransform(attachLimb.SimPosition, attachLimb.Rotation);
|
||||
ragdoll.AddLimb(huskAppendage);
|
||||
ragdoll.AddJoint(jointParams);
|
||||
appendage.Add(huskAppendage);
|
||||
}
|
||||
}
|
||||
return appendage;
|
||||
}
|
||||
|
||||
+106
-19
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -214,7 +215,6 @@ namespace Barotrauma
|
||||
[Serialize("", IsPropertySaveable.No)]
|
||||
public Identifier DialogFlag { get; private set; }
|
||||
|
||||
|
||||
[Serialize("", IsPropertySaveable.No)]
|
||||
public Identifier Tag { get; private set; }
|
||||
|
||||
@@ -276,6 +276,47 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public class Description
|
||||
{
|
||||
public enum TargetType
|
||||
{
|
||||
Any,
|
||||
Self,
|
||||
OtherCharacter
|
||||
}
|
||||
|
||||
public readonly LocalizedString Text;
|
||||
public readonly Identifier TextTag;
|
||||
public readonly float MinStrength, MaxStrength;
|
||||
public readonly TargetType Target;
|
||||
|
||||
public Description(ContentXElement element, AfflictionPrefab affliction)
|
||||
{
|
||||
TextTag = element.GetAttributeIdentifier("textidentifier", Identifier.Empty);
|
||||
if (!TextTag.IsEmpty)
|
||||
{
|
||||
Text = TextManager.Get(TextTag);
|
||||
}
|
||||
string text = element.GetAttributeString("text", string.Empty);
|
||||
if (!text.IsNullOrEmpty())
|
||||
{
|
||||
Text = Text?.Fallback(text) ?? text;
|
||||
}
|
||||
else if (TextTag.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in affliction \"{affliction.Identifier}\" - no text defined for one of the descriptions.");
|
||||
}
|
||||
|
||||
MinStrength = element.GetAttributeFloat(nameof(MinStrength), 0.0f);
|
||||
MaxStrength = element.GetAttributeFloat(nameof(MaxStrength), 100.0f);
|
||||
if (MinStrength >= MaxStrength)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in affliction \"{affliction.Identifier}\" - max strength is not larger than min.");
|
||||
}
|
||||
Target = element.GetAttributeEnum(nameof(Target), TargetType.Any);
|
||||
}
|
||||
}
|
||||
|
||||
public class PeriodicEffect
|
||||
{
|
||||
public readonly List<StatusEffect> StatusEffects = new List<StatusEffect>();
|
||||
@@ -313,7 +354,6 @@ namespace Barotrauma
|
||||
|
||||
public static readonly PrefabCollection<AfflictionPrefab> Prefabs = new PrefabCollection<AfflictionPrefab>();
|
||||
|
||||
private bool disposed = false;
|
||||
public override void Dispose() { }
|
||||
|
||||
public static IEnumerable<AfflictionPrefab> List => Prefabs;
|
||||
@@ -330,15 +370,22 @@ namespace Barotrauma
|
||||
//(e.g. mental health problems on head, lack of oxygen on torso...)
|
||||
public readonly LimbType IndicatorLimb;
|
||||
|
||||
public readonly LocalizedString Name, Description;
|
||||
public readonly LocalizedString Name;
|
||||
public readonly Identifier TranslationIdentifier;
|
||||
public readonly bool IsBuff;
|
||||
public readonly bool AffectMachines;
|
||||
public readonly bool HealableInMedicalClinic;
|
||||
public readonly float HealCostMultiplier;
|
||||
public readonly int BaseHealCost;
|
||||
public readonly bool ShowBarInHealthMenu;
|
||||
|
||||
public readonly LocalizedString CauseOfDeathDescription, SelfCauseOfDeathDescription;
|
||||
|
||||
private readonly LocalizedString defaultDescription;
|
||||
public readonly ImmutableList<Description> Descriptions;
|
||||
|
||||
public readonly bool HideIconAfterDelay;
|
||||
|
||||
//how high the strength has to be for the affliction to take affect
|
||||
public readonly float ActivationThreshold = 0.0f;
|
||||
//how high the strength has to be for the affliction icon to be shown in the UI
|
||||
@@ -355,6 +402,11 @@ namespace Barotrauma
|
||||
//how strong the affliction needs to be before bots attempt to treat it
|
||||
public readonly float TreatmentThreshold = 5.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Bots will not try to treat the affliction if the character has any of these afflictions
|
||||
/// </summary>
|
||||
public ImmutableHashSet<Identifier> IgnoreTreatmentIfAfflictedBy;
|
||||
|
||||
/// <summary>
|
||||
/// The affliction is automatically removed after this time. 0 = unlimited
|
||||
/// </summary>
|
||||
@@ -384,6 +436,8 @@ namespace Barotrauma
|
||||
|
||||
private readonly ConstructorInfo constructor;
|
||||
|
||||
public readonly bool ResetBetweenRounds;
|
||||
|
||||
public IEnumerable<KeyValuePair<Identifier, float>> TreatmentSuitability
|
||||
{
|
||||
get
|
||||
@@ -411,13 +465,16 @@ namespace Barotrauma
|
||||
{
|
||||
Name = Name.Fallback(fallbackName);
|
||||
}
|
||||
Description = TextManager.Get($"AfflictionDescription.{TranslationIdentifier}");
|
||||
defaultDescription = TextManager.Get($"AfflictionDescription.{TranslationIdentifier}");
|
||||
string fallbackDescription = element.GetAttributeString("description", "");
|
||||
if (!string.IsNullOrEmpty(fallbackDescription))
|
||||
{
|
||||
Description = Description.Fallback(fallbackDescription);
|
||||
defaultDescription = defaultDescription.Fallback(fallbackDescription);
|
||||
}
|
||||
IsBuff = element.GetAttributeBool("isbuff", false);
|
||||
IsBuff = element.GetAttributeBool(nameof(IsBuff), false);
|
||||
AffectMachines = element.GetAttributeBool(nameof(AffectMachines), true);
|
||||
|
||||
ShowBarInHealthMenu = element.GetAttributeBool("showbarinhealthmenu", true);
|
||||
|
||||
HealableInMedicalClinic = element.GetAttributeBool("healableinmedicalclinic",
|
||||
!IsBuff &&
|
||||
@@ -426,6 +483,8 @@ namespace Barotrauma
|
||||
HealCostMultiplier = element.GetAttributeFloat(nameof(HealCostMultiplier), 1f);
|
||||
BaseHealCost = element.GetAttributeInt(nameof(BaseHealCost), 0);
|
||||
|
||||
IgnoreTreatmentIfAfflictedBy = element.GetAttributeIdentifierArray(nameof(IgnoreTreatmentIfAfflictedBy), Array.Empty<Identifier>()).ToImmutableHashSet();
|
||||
|
||||
Duration = element.GetAttributeFloat(nameof(Duration), 0.0f);
|
||||
|
||||
if (element.GetAttribute("nameidentifier") != null)
|
||||
@@ -443,28 +502,33 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
ActivationThreshold = element.GetAttributeFloat("activationthreshold", 0.0f);
|
||||
ShowIconThreshold = element.GetAttributeFloat("showiconthreshold", Math.Max(ActivationThreshold, 0.05f));
|
||||
ShowIconToOthersThreshold = element.GetAttributeFloat("showicontoothersthreshold", ShowIconThreshold);
|
||||
MaxStrength = element.GetAttributeFloat("maxstrength", 100.0f);
|
||||
GrainBurst = element.GetAttributeFloat(nameof(GrainBurst).ToLowerInvariant(), 0.0f);
|
||||
HideIconAfterDelay = element.GetAttributeBool(nameof(HideIconAfterDelay), false);
|
||||
|
||||
ShowInHealthScannerThreshold = element.GetAttributeFloat("showinhealthscannerthreshold",
|
||||
ActivationThreshold = element.GetAttributeFloat(nameof(ActivationThreshold), 0.0f);
|
||||
ShowIconThreshold = element.GetAttributeFloat(nameof(ShowIconThreshold), Math.Max(ActivationThreshold, 0.05f));
|
||||
ShowIconToOthersThreshold = element.GetAttributeFloat(nameof(ShowIconToOthersThreshold), ShowIconThreshold);
|
||||
MaxStrength = element.GetAttributeFloat(nameof(MaxStrength), 100.0f);
|
||||
GrainBurst = element.GetAttributeFloat(nameof(GrainBurst), 0.0f);
|
||||
|
||||
ShowInHealthScannerThreshold = element.GetAttributeFloat(nameof(ShowInHealthScannerThreshold),
|
||||
Math.Max(ActivationThreshold, AfflictionType == "talentbuff" ? float.MaxValue : ShowIconToOthersThreshold));
|
||||
TreatmentThreshold = element.GetAttributeFloat("treatmentthreshold", Math.Max(ActivationThreshold, 5.0f));
|
||||
TreatmentThreshold = element.GetAttributeFloat(nameof(TreatmentThreshold), Math.Max(ActivationThreshold, 5.0f));
|
||||
|
||||
DamageOverlayAlpha = element.GetAttributeFloat("damageoverlayalpha", 0.0f);
|
||||
BurnOverlayAlpha = element.GetAttributeFloat("burnoverlayalpha", 0.0f);
|
||||
DamageOverlayAlpha = element.GetAttributeFloat(nameof(DamageOverlayAlpha), 0.0f);
|
||||
BurnOverlayAlpha = element.GetAttributeFloat(nameof(BurnOverlayAlpha), 0.0f);
|
||||
|
||||
KarmaChangeOnApplied = element.GetAttributeFloat("karmachangeonapplied", 0.0f);
|
||||
KarmaChangeOnApplied = element.GetAttributeFloat(nameof(KarmaChangeOnApplied), 0.0f);
|
||||
|
||||
CauseOfDeathDescription = TextManager.Get($"AfflictionCauseOfDeath.{TranslationIdentifier}").Fallback(element.GetAttributeString("causeofdeathdescription", ""));
|
||||
SelfCauseOfDeathDescription = TextManager.Get($"AfflictionCauseOfDeathSelf.{TranslationIdentifier}").Fallback(element.GetAttributeString("selfcauseofdeathdescription", ""));
|
||||
|
||||
IconColors = element.GetAttributeColorArray("iconcolors", null);
|
||||
AfflictionOverlayAlphaIsLinear = element.GetAttributeBool("afflictionoverlayalphaislinear", false);
|
||||
AchievementOnRemoved = element.GetAttributeIdentifier("achievementonremoved", "");
|
||||
IconColors = element.GetAttributeColorArray(nameof(IconColors), null);
|
||||
AfflictionOverlayAlphaIsLinear = element.GetAttributeBool(nameof(AfflictionOverlayAlphaIsLinear), false);
|
||||
AchievementOnRemoved = element.GetAttributeIdentifier(nameof(AchievementOnRemoved), "");
|
||||
|
||||
ResetBetweenRounds = element.GetAttributeBool("resetbetweenrounds", false);
|
||||
|
||||
List<Description> descriptions = new List<Description>();
|
||||
foreach (var subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
@@ -481,15 +545,38 @@ namespace Barotrauma
|
||||
case "effect":
|
||||
case "periodiceffect":
|
||||
break;
|
||||
case "description":
|
||||
descriptions.Add(new Description(subElement, this));
|
||||
break;
|
||||
default:
|
||||
DebugConsole.AddWarning($"Unrecognized element in affliction \"{Identifier}\" ({subElement.Name})");
|
||||
break;
|
||||
}
|
||||
}
|
||||
Descriptions = descriptions.ToImmutableList();
|
||||
|
||||
constructor = type.GetConstructor(new[] { typeof(AfflictionPrefab), typeof(float) });
|
||||
}
|
||||
|
||||
public LocalizedString GetDescription(float strength, Description.TargetType targetType)
|
||||
{
|
||||
foreach (var description in Descriptions)
|
||||
{
|
||||
if (strength < description.MinStrength || strength > description.MaxStrength) { continue; }
|
||||
switch (targetType)
|
||||
{
|
||||
case Description.TargetType.Self:
|
||||
if (description.Target == Description.TargetType.OtherCharacter) { continue; }
|
||||
break;
|
||||
case Description.TargetType.OtherCharacter:
|
||||
if (description.Target == Description.TargetType.Self) { continue; }
|
||||
break;
|
||||
}
|
||||
return description.Text;
|
||||
}
|
||||
return defaultDescription;
|
||||
}
|
||||
|
||||
public static void LoadAllEffects()
|
||||
{
|
||||
Prefabs.ForEach(p => p.LoadEffects());
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace Barotrauma
|
||||
|
||||
public bool DoesBleed
|
||||
{
|
||||
get => Character.Params.Health.DoesBleed;
|
||||
get => Character.Params.Health.DoesBleed && !Character.Params.IsMachine;
|
||||
private set => Character.Params.Health.DoesBleed = value;
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ namespace Barotrauma
|
||||
|
||||
public bool IsUnconscious
|
||||
{
|
||||
get { return (Vitality <= 0.0f || Character.IsDead) && !Character.HasAbilityFlag(AbilityFlags.AlwaysStayConscious); }
|
||||
get { return Character.IsDead || (Vitality <= 0.0f && !Character.HasAbilityFlag(AbilityFlags.AlwaysStayConscious)); }
|
||||
}
|
||||
|
||||
public float PressureKillDelay { get; private set; } = 5.0f;
|
||||
@@ -145,9 +145,20 @@ namespace Barotrauma
|
||||
private float vitality;
|
||||
public float Vitality
|
||||
{
|
||||
get
|
||||
{
|
||||
return Character.IsDead ? minVitality : vitality;
|
||||
get
|
||||
{
|
||||
if (Character.IsDead)
|
||||
{
|
||||
return minVitality;
|
||||
}
|
||||
|
||||
if (Character.HasAbilityFlag(AbilityFlags.CanNotDieToAfflictions))
|
||||
{
|
||||
return Math.Max(vitality, MinVitality + 1);
|
||||
}
|
||||
|
||||
return vitality;
|
||||
|
||||
}
|
||||
private set
|
||||
{
|
||||
@@ -545,7 +556,7 @@ namespace Barotrauma
|
||||
amount -= reduceAmount;
|
||||
if (treatmentAction != null)
|
||||
{
|
||||
if (treatmentAction.Value == ActionType.OnUse)
|
||||
if (treatmentAction.Value == ActionType.OnUse || treatmentAction.Value == ActionType.OnSuccess)
|
||||
{
|
||||
matchingAffliction.AppliedAsSuccessfulTreatmentTime = Timing.TotalTime;
|
||||
}
|
||||
@@ -690,10 +701,18 @@ namespace Barotrauma
|
||||
|
||||
private void AddLimbAffliction(LimbHealth limbHealth, Affliction newAffliction, bool allowStacking = true)
|
||||
{
|
||||
if (Character.Params.IsMachine && !newAffliction.Prefab.AffectMachines) { return; }
|
||||
if (!DoesBleed && newAffliction is AfflictionBleeding) { return; }
|
||||
if (!Character.NeedsOxygen && newAffliction.Prefab == AfflictionPrefab.OxygenLow) { return; }
|
||||
if (Character.Params.Health.StunImmunity && newAffliction.Prefab.AfflictionType == "stun") { return; }
|
||||
if (Character.Params.Health.StunImmunity && newAffliction.Prefab.AfflictionType == "stun")
|
||||
{
|
||||
if (Character.EmpVulnerability <= 0 || GetAfflictionStrength("emp", allowLimbAfflictions: false) <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (Character.Params.Health.PoisonImmunity && newAffliction.Prefab.AfflictionType == "poison") { return; }
|
||||
if (Character.EmpVulnerability <= 0 && newAffliction.Prefab.AfflictionType == "emp") { return; }
|
||||
if (newAffliction.Prefab is AfflictionPrefabHusk huskPrefab)
|
||||
{
|
||||
if (huskPrefab.TargetSpecies.None(s => s == Character.SpeciesName))
|
||||
@@ -884,25 +903,36 @@ namespace Barotrauma
|
||||
{
|
||||
if (!Character.NeedsOxygen) { return; }
|
||||
|
||||
float oxygenlowResistance = GetResistance(oxygenLowAffliction.Prefab);
|
||||
float prevOxygen = OxygenAmount;
|
||||
if (IsUnconscious)
|
||||
{
|
||||
//clamp above 0.1 (no amount of oxygen low resistance should keep the character alive indefinitely)
|
||||
float decreaseSpeed = Math.Max(0.1f, 1f - oxygenlowResistance);
|
||||
//the character dies of oxygen deprivation in 100 seconds after losing consciousness
|
||||
OxygenAmount = MathHelper.Clamp(OxygenAmount - 1.0f * deltaTime, -100.0f, 100.0f);
|
||||
OxygenAmount = MathHelper.Clamp(OxygenAmount - decreaseSpeed * deltaTime, -100.0f, 100.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
float decreaseSpeed = -5.0f;
|
||||
float increaseSpeed = 10.0f;
|
||||
float oxygenlowResistance = GetResistance(oxygenLowAffliction.Prefab);
|
||||
decreaseSpeed *= (1f - oxygenlowResistance);
|
||||
increaseSpeed *= (1f + oxygenlowResistance);
|
||||
OxygenAmount = MathHelper.Clamp(OxygenAmount + deltaTime * (Character.OxygenAvailable < InsufficientOxygenThreshold ? decreaseSpeed : increaseSpeed), -100.0f, 100.0f);
|
||||
float holdBreathMultiplier = Character.GetStatValue(StatTypes.HoldBreathMultiplier);
|
||||
if (holdBreathMultiplier <= -1.0f)
|
||||
{
|
||||
OxygenAmount = -100.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
decreaseSpeed /= 1.0f + Character.GetStatValue(StatTypes.HoldBreathMultiplier);
|
||||
OxygenAmount = MathHelper.Clamp(OxygenAmount + deltaTime * (Character.OxygenAvailable < InsufficientOxygenThreshold ? decreaseSpeed : increaseSpeed), -100.0f, 100.0f);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateOxygenProjSpecific(prevOxygen, deltaTime);
|
||||
}
|
||||
|
||||
|
||||
partial void UpdateOxygenProjSpecific(float prevOxygen, float deltaTime);
|
||||
|
||||
partial void UpdateBleedingProjSpecific(AfflictionBleeding affliction, Limb targetLimb, float deltaTime);
|
||||
@@ -1078,6 +1108,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
if (strength <= affliction.Prefab.TreatmentThreshold) { continue; }
|
||||
if (afflictions.Any(otherAffliction => affliction.Prefab.IgnoreTreatmentIfAfflictedBy.Contains(otherAffliction.Key.Identifier))) { continue; }
|
||||
|
||||
if (ignoreHiddenAfflictions)
|
||||
{
|
||||
@@ -1233,6 +1264,7 @@ namespace Barotrauma
|
||||
var affliction = kvp.Key;
|
||||
var limbHealth = kvp.Value;
|
||||
if (affliction.Strength <= 0.0f || limbHealth != null) { continue; }
|
||||
if (kvp.Key.Prefab.ResetBetweenRounds) { continue; }
|
||||
healthElement.Add(new XElement("Affliction",
|
||||
new XAttribute("identifier", affliction.Identifier),
|
||||
new XAttribute("strength", affliction.Strength.ToString("G", CultureInfo.InvariantCulture))));
|
||||
|
||||
@@ -79,27 +79,35 @@ namespace Barotrauma
|
||||
|
||||
public ref readonly ImmutableArray<Identifier> ParsedAfflictionTypes => ref parsedAfflictionTypes;
|
||||
|
||||
public DamageModifier(XElement element, string parentDebugName)
|
||||
public DamageModifier(XElement element, string parentDebugName, bool checkErrors = true)
|
||||
{
|
||||
Deserialize(element);
|
||||
if (element.Attribute("afflictionnames") != null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in DamageModifier config (" + parentDebugName + ") - define afflictions using identifiers or types instead of names.");
|
||||
}
|
||||
foreach (var afflictionType in parsedAfflictionTypes)
|
||||
if (checkErrors)
|
||||
{
|
||||
if (!AfflictionPrefab.Prefabs.Any(p => p.AfflictionType == afflictionType))
|
||||
foreach (var afflictionType in parsedAfflictionTypes)
|
||||
{
|
||||
createWarningOrError($"Potentially invalid damage modifier in \"{parentDebugName}\". Could not find any afflictions of the type \"{afflictionType}\". Did you mean to use an affliction identifier instead?");
|
||||
}
|
||||
}
|
||||
foreach (var afflictionIdentifier in parsedAfflictionIdentifiers)
|
||||
{
|
||||
if (!AfflictionPrefab.Prefabs.ContainsKey(afflictionIdentifier))
|
||||
{
|
||||
createWarningOrError($"Potentially invalid damage modifier in \"{parentDebugName}\". Could not find any afflictions with the identifier \"{afflictionIdentifier}\". Did you mean to use an affliction type instead?");
|
||||
if (!AfflictionPrefab.Prefabs.Any(p => p.AfflictionType == afflictionType))
|
||||
{
|
||||
createWarningOrError($"Potentially invalid damage modifier in \"{parentDebugName}\". Could not find any afflictions of the type \"{afflictionType}\". Did you mean to use an affliction identifier instead?");
|
||||
}
|
||||
}
|
||||
foreach (var afflictionIdentifier in parsedAfflictionIdentifiers)
|
||||
{
|
||||
if (!AfflictionPrefab.Prefabs.ContainsKey(afflictionIdentifier))
|
||||
{
|
||||
createWarningOrError($"Potentially invalid damage modifier in \"{parentDebugName}\". Could not find any afflictions with the identifier \"{afflictionIdentifier}\". Did you mean to use an affliction type instead?");
|
||||
}
|
||||
}
|
||||
if (!parsedAfflictionTypes.Any() && !parsedAfflictionIdentifiers.Any())
|
||||
{
|
||||
createWarningOrError($"Potentially invalid damage modifier in \"{parentDebugName}\". Neither affliction types of identifiers defined.");
|
||||
}
|
||||
}
|
||||
|
||||
static void createWarningOrError(string msg)
|
||||
{
|
||||
#if DEBUG
|
||||
|
||||
Reference in New Issue
Block a user