Unstable 0.1500.0.0

This commit is contained in:
Markus Isberg
2021-08-26 21:08:21 +09:00
parent 265a2e7ab3
commit 501e02c026
245 changed files with 9775 additions and 2034 deletions
@@ -237,6 +237,26 @@ namespace Barotrauma
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
}
public float GetStatValue(StatTypes statType)
{
if (!(GetViableEffect() is AfflictionPrefab.Effect currentEffect)) { return 0.0f; }
if (currentEffect.AfflictionStatValues.TryGetValue(statType, out var value))
{
return MathHelper.Lerp(
value.minValue,
value.maxValue,
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
}
return 0.0f;
}
private AfflictionPrefab.Effect GetViableEffect()
{
if (Strength < Prefab.ActivationThreshold) { return null; }
return GetActiveEffect();
}
public virtual void Update(CharacterHealth characterHealth, Limb targetLimb, float deltaTime)
{
foreach (AfflictionPrefab.PeriodicEffect periodicEffect in Prefab.PeriodicEffects)
@@ -264,7 +284,11 @@ namespace Barotrauma
if (currentEffect.StrengthChange < 0) // Reduce diminishing of buffs if boosted
{
_strength += currentEffect.StrengthChange * deltaTime * StrengthDiminishMultiplier;
float durationMultiplier = 1 / (1 + (Prefab.IsBuff ? characterHealth.Character.GetStatValue(StatTypes.BuffDurationMultiplier)
: characterHealth.Character.GetStatValue(StatTypes.DebuffDurationMultiplier)));
_strength += currentEffect.StrengthChange * deltaTime * StrengthDiminishMultiplier * durationMultiplier;
}
else // Reduce strengthening of afflictions if resistant
{
@@ -212,6 +212,25 @@ namespace Barotrauma
husk.Info.TeamID = CharacterTeamType.None;
}
if (Prefab is AfflictionPrefabHusk huskPrefab)
{
if (huskPrefab.ControlHusk)
{
#if SERVER
var client = GameMain.Server?.ConnectedClients.FirstOrDefault(c => c.CharacterInfo.Character == character);
if (client != null)
{
GameMain.Server.SetClientCharacter(client, husk);
}
#else
if (!character.IsRemotelyControlled && character == Character.Controlled)
{
Character.Controlled = husk;
}
#endif
}
}
foreach (Limb limb in husk.AnimController.Limbs)
{
if (limb.type == LimbType.None)
@@ -229,15 +248,19 @@ namespace Barotrauma
}
}
if ((Prefab as AfflictionPrefabHusk)?.TransferBuffs ?? false)
{
foreach (Affliction affliction in character.CharacterHealth.Afflictions)
{
if (affliction.Prefab.IsBuff)
{
husk.CharacterHealth.ApplyAffliction(null, affliction.Prefab.Instantiate(affliction.Strength));
}
}
}
if (character.Inventory != null && husk.Inventory != null)
{
if (character.Inventory.Capacity != husk.Inventory.Capacity)
{
string errorMsg = "Failed to move items from the source character's inventory into a husk's inventory (inventory sizes don't match)";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("AfflictionHusk.CreateAIHusk:InventoryMismatch", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
yield return CoroutineStatus.Success;
}
for (int i = 0; i < character.Inventory.Capacity && i < husk.Inventory.Capacity; i++)
{
character.Inventory.GetItemsAt(i).ForEachMod(item => husk.Inventory.TryPutItem(item, i, true, false, null));
@@ -5,6 +5,7 @@ using System.Reflection;
using System.Xml.Linq;
using System.Linq;
using System.Security.Cryptography;
using Barotrauma.Abilities;
namespace Barotrauma
{
@@ -91,9 +92,11 @@ namespace Barotrauma
AttachLimbType = LimbType.None;
}
TransferBuffs = element.GetAttributeBool("transferbuffs", true);
SendMessages = element.GetAttributeBool("sendmessages", true);
CauseSpeechImpediment = element.GetAttributeBool("causespeechimpediment", true);
NeedsAir = element.GetAttributeBool("needsair", false);
ControlHusk = element.GetAttributeBool("controlhusk", false);
}
// Use any of these to define which limb the appendage is attached to.
@@ -106,9 +109,11 @@ namespace Barotrauma
public readonly string[] TargetSpecies;
public const string Tag = "[speciesname]";
public readonly bool TransferBuffs;
public readonly bool SendMessages;
public readonly bool CauseSpeechImpediment;
public readonly bool NeedsAir;
public readonly bool ControlHusk;
}
class AfflictionPrefab : IPrefab, IDisposable, IHasUintIdentifier
@@ -116,83 +121,93 @@ namespace Barotrauma
public class Effect
{
//this effect is applied when the strength is within this range
public float MinStrength, MaxStrength;
[Serialize(0.0f, false)]
public float MinStrength { get; private set; }
[Serialize(0.0f, false)]
public float MaxStrength { get; private set; }
[Serialize(0.0f, false)]
public float MinVitalityDecrease { get; private set; }
[Serialize(0.0f, false)]
public float MaxVitalityDecrease { get; private set; }
public readonly float MinVitalityDecrease = 0.0f;
public readonly float MaxVitalityDecrease = 0.0f;
//how much the strength of the affliction changes per second
public readonly float StrengthChange = 0.0f;
[Serialize(0.0f, false)]
public float StrengthChange { get; private set; }
public readonly bool MultiplyByMaxVitality;
[Serialize(false, false)]
public bool MultiplyByMaxVitality { get; private set; }
public float MinScreenBlurStrength, MaxScreenBlurStrength;
public float MinScreenDistortStrength, MaxScreenDistortStrength;
public float MinGrainStrength, MaxGrainStrength;
public float MinRadialDistortStrength, MaxRadialDistortStrength;
public float MinChromaticAberrationStrength, MaxChromaticAberrationStrength;
public float MinSpeedMultiplier, MaxSpeedMultiplier;
public float MinBuffMultiplier, MaxBuffMultiplier;
[Serialize(0.0f, false)]
public float MinScreenBlurStrength { get; private set; }
public float MinSkillMultiplier, MaxSkillMultiplier;
[Serialize(0.0f, false)]
public float MaxScreenBlurStrength { get; private set; }
public float MinResistance, MaxResistance;
public string ResistanceFor;
public string DialogFlag;
[Serialize(0.0f, false)]
public float MinScreenDistortStrength { get; private set; }
[Serialize(0.0f, false)]
public float MaxScreenDistortStrength { get; private set; }
[Serialize(0.0f, false)]
public float MinRadialDistortStrength { get; private set; }
[Serialize(0.0f, false)]
public float MaxRadialDistortStrength { get; private set; }
[Serialize(0.0f, false)]
public float MinChromaticAberrationStrength { get; private set; }
[Serialize(0.0f, false)]
public float MaxChromaticAberrationStrength { get; private set; }
[Serialize(0.0f, false)]
public float MinGrainStrength { get; private set; }
[Serialize(0.0f, false)]
public float MaxGrainStrength { get; private set; }
[Serialize(1.0f, false)]
public float MinBuffMultiplier { get; private set; }
[Serialize(1.0f, false)]
public float MaxBuffMultiplier { get; private set; }
[Serialize(1.0f, false)]
public float MinSpeedMultiplier { get; private set; }
[Serialize(1.0f, false)]
public float MaxSpeedMultiplier { get; private set; }
[Serialize(1.0f, false)]
public float MinSkillMultiplier { get; private set; }
[Serialize(1.0f, false)]
public float MaxSkillMultiplier { get; private set; }
[Serialize("", false)]
public string ResistanceFor { get; private set; }
[Serialize(0.0f, false)]
public float MinResistance { get; private set; }
[Serialize(0.0f, false)]
public float MaxResistance { get; private set; }
[Serialize("", false)]
public string DialogFlag { get; private set; }
public readonly Dictionary<StatTypes, (float minValue, float maxValue)> AfflictionStatValues = new Dictionary<StatTypes, (float minValue, float maxValue)>();
//statuseffects applied on the character when the affliction is active
public readonly List<StatusEffect> StatusEffects = new List<StatusEffect>();
public Effect(XElement element, string parentDebugName)
{
MinStrength = element.GetAttributeFloat("minstrength", 0);
MaxStrength = element.GetAttributeFloat("maxstrength", 0);
MultiplyByMaxVitality = element.GetAttributeBool("multiplybymaxvitality", false);
MinVitalityDecrease = element.GetAttributeFloat("minvitalitydecrease", 0.0f);
MaxVitalityDecrease = element.GetAttributeFloat("maxvitalitydecrease", 0.0f);
MaxVitalityDecrease = Math.Max(MinVitalityDecrease, MaxVitalityDecrease);
MinScreenDistortStrength = element.GetAttributeFloat("minscreendistort", 0.0f);
MaxScreenDistortStrength = element.GetAttributeFloat("maxscreendistort", 0.0f);
MaxScreenDistortStrength = Math.Max(MinScreenDistortStrength, MaxScreenDistortStrength);
MinRadialDistortStrength = element.GetAttributeFloat("minradialdistort", 0.0f);
MaxRadialDistortStrength = element.GetAttributeFloat("maxradialdistort", 0.0f);
MaxRadialDistortStrength = Math.Max(MinRadialDistortStrength, MaxRadialDistortStrength);
MinChromaticAberrationStrength = element.GetAttributeFloat("minchromaticaberration", 0.0f);
MaxChromaticAberrationStrength = element.GetAttributeFloat("maxchromaticaberration", 0.0f);
MaxChromaticAberrationStrength = Math.Max(MinChromaticAberrationStrength, MaxChromaticAberrationStrength);
MinGrainStrength = element.GetAttributeFloat(nameof(MinGrainStrength).ToLower(), 0.0f);
MaxGrainStrength = element.GetAttributeFloat(nameof(MaxGrainStrength).ToLower(), 0.0f);
MaxGrainStrength = Math.Max(MinGrainStrength, MaxGrainStrength);
MinScreenBlurStrength = element.GetAttributeFloat("minscreenblur", 0.0f);
MaxScreenBlurStrength = element.GetAttributeFloat("maxscreenblur", 0.0f);
MaxScreenBlurStrength = Math.Max(MinScreenBlurStrength, MaxScreenBlurStrength);
MinSkillMultiplier = element.GetAttributeFloat("minskillmultiplier", 1.0f);
MaxSkillMultiplier = element.GetAttributeFloat("maxskillmultiplier", 1.0f);
ResistanceFor = element.GetAttributeString("resistancefor", "");
MinResistance = element.GetAttributeFloat("minresistance", 0.0f);
MaxResistance = element.GetAttributeFloat("maxresistance", 0.0f);
MaxResistance = Math.Max(MinResistance, MaxResistance);
MinSpeedMultiplier = element.GetAttributeFloat("minspeedmultiplier", 1.0f);
MaxSpeedMultiplier = element.GetAttributeFloat("maxspeedmultiplier", 1.0f);
MaxSpeedMultiplier = Math.Max(MinSpeedMultiplier, MaxSpeedMultiplier);
MinBuffMultiplier = element.GetAttributeFloat("minbuffmultiplier", 1.0f);
MaxBuffMultiplier = element.GetAttributeFloat("maxbuffmultiplier", 1.0f);
MaxBuffMultiplier = Math.Max(MinBuffMultiplier, MaxBuffMultiplier);
DialogFlag = element.GetAttributeString("dialogflag", "");
StrengthChange = element.GetAttributeFloat("strengthchange", 0.0f);
SerializableProperty.DeserializeProperties(this, element);
foreach (XElement subElement in element.Elements())
{
@@ -201,6 +216,15 @@ namespace Barotrauma
case "statuseffect":
StatusEffects.Add(StatusEffect.Load(subElement, parentDebugName));
break;
case "statvalue":
var statType = CharacterAbilityGroup.ParseStatType(subElement.GetAttributeString("stattype", ""), parentDebugName);
float defaultValue = subElement.GetAttributeFloat("value", 0f);
float minValue = subElement.GetAttributeFloat("minvalue", defaultValue);
float maxValue = subElement.GetAttributeFloat("maxvalue", defaultValue);
AfflictionStatValues.TryAdd(statType, (minValue, maxValue));
break;
}
}
}
@@ -590,7 +614,7 @@ namespace Barotrauma
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).ToLower(), 0.0f);
GrainBurst = element.GetAttributeFloat(nameof(GrainBurst).ToLowerInvariant(), 0.0f);
ShowInHealthScannerThreshold = element.GetAttributeFloat("showinhealthscannerthreshold", Math.Max(ActivationThreshold, 0.05f));
TreatmentThreshold = element.GetAttributeFloat("treatmentthreshold", Math.Max(ActivationThreshold, 5.0f));
@@ -116,15 +116,15 @@ namespace Barotrauma
private set => Character.Params.Health.CrushDepth = value;
}
private List<LimbHealth> limbHealths = new List<LimbHealth>();
private readonly List<LimbHealth> limbHealths = new List<LimbHealth>();
//non-limb-specific afflictions
private List<Affliction> afflictions = new List<Affliction>();
private readonly List<Affliction> afflictions = new List<Affliction>();
/// <summary>
/// Note: returns only the non-limb-secific afflictions. Use GetAllAfflictions or some other method for getting also the limb-specific afflictions.
/// </summary>
public IEnumerable<Affliction> Afflictions => afflictions;
private HashSet<Affliction> irremovableAfflictions = new HashSet<Affliction>();
private readonly HashSet<Affliction> irremovableAfflictions = new HashSet<Affliction>();
private Affliction bloodlossAffliction;
private Affliction oxygenLowAffliction;
private Affliction pressureAffliction;
@@ -151,6 +151,7 @@ namespace Barotrauma
max += Character.Info.Job.Prefab.VitalityModifier;
}
max *= Character.StaticHealthMultiplier;
max *= 1f + Character.GetStatValue(StatTypes.MaximumHealthMultiplier);
return max * Character.HealthMultiplier;
}
}
@@ -434,10 +435,21 @@ namespace Barotrauma
float temp = afflictions[i].GetResistance(resistanceId);
if (temp > resistance) resistance = temp;
}
resistance = 1 - ((1 - resistance) * Character.GetAbilityResistance(resistanceId));
return resistance;
}
public float GetStatValue(StatTypes statType)
{
float value = 0f;
for (int i = 0; i < afflictions.Count; i++)
{
value += afflictions[i].GetStatValue(statType);
}
return value;
}
private readonly List<Affliction> matchingAfflictions = new List<Affliction>();
public void ReduceAffliction(Limb targetLimb, string affliction, float amount)
{
@@ -468,6 +480,11 @@ namespace Barotrauma
for (int i = matchingAfflictions.Count - 1; i >= 0; i--)
{
var matchingAffliction = matchingAfflictions[i];
// kind of bad to create a tuple every time, but I can't think of another way to easily do this
var afflictionReduction = (matchingAffliction, reduceAmount);
Character.CheckTalents(AbilityEffectType.OnReduceAffliction, afflictionReduction);
if (matchingAffliction.Strength < reduceAmount)
{
float surplus = reduceAmount - matchingAffliction.Strength;
@@ -539,9 +556,9 @@ namespace Barotrauma
else
{
// Instead of using the limbhealth count here, I think it's best to define the max vitality per limb roughly with a constant value.
// Therefore with e.g. 80 health, the max damage per limb would be 20.
// Having at least 20 damage on both legs would cause maximum limping.
float max = MaxVitality / 4;
// Therefore with e.g. 80 health, the max damage per limb would be 40.
// Having at least 40 damage on both legs would cause maximum limping.
float max = MaxVitality / 2;
if (string.IsNullOrEmpty(afflictionType))
{
float damage = GetAfflictionStrength("damage", limb, true);
@@ -738,7 +755,15 @@ namespace Barotrauma
affliction.DamagePerSecondTimer += deltaTime;
Character.StackSpeedMultiplier(affliction.GetSpeedMultiplier());
}
Character.StackSpeedMultiplier(1f + Character.GetStatValue(StatTypes.MovementSpeed));
// maybe a bit of a hacky way to do this. should inquire if there is a better way. M61T
if (Character.InWater)
{
Character.StackSpeedMultiplier(1f + Character.GetStatValue(StatTypes.SwimmingSpeed));
}
UpdateLimbAfflictionOverlays();
CalculateVitality();
@@ -825,8 +850,8 @@ namespace Barotrauma
{
if (Unkillable || Character.GodMode) { return; }
var causeOfDeath = GetCauseOfDeath();
Character.Kill(causeOfDeath.First, causeOfDeath.Second);
var (type, affliction) = GetCauseOfDeath();
Character.Kill(type, affliction);
#if CLIENT
DisplayVitalityDelay = 0.0f;
DisplayedVitality = Vitality;
@@ -859,7 +884,7 @@ namespace Barotrauma
}
}
public Pair<CauseOfDeathType, Affliction> GetCauseOfDeath()
public (CauseOfDeathType type, Affliction affliction) GetCauseOfDeath()
{
List<Affliction> currentAfflictions = GetAllAfflictions(true);
@@ -880,7 +905,7 @@ namespace Barotrauma
causeOfDeath = Character.AnimController.InWater ? CauseOfDeathType.Drowning : CauseOfDeathType.Suffocation;
}
return new Pair<CauseOfDeathType, Affliction>(causeOfDeath, strongestAffliction);
return (causeOfDeath, strongestAffliction);
}
// TODO: this method is called a lot (every half second) -> optimize, don't create new class instances and lists every time!
@@ -968,7 +993,7 @@ namespace Barotrauma
}
private readonly List<Affliction> activeAfflictions = new List<Affliction>();
private readonly List<Pair<LimbHealth, Affliction>> limbAfflictions = new List<Pair<LimbHealth, Affliction>>();
private readonly List<(LimbHealth limbHealth, Affliction affliction)> limbAfflictions = new List<(LimbHealth limbHealth, Affliction affliction)>();
public void ServerWrite(IWriteMessage msg)
{
activeAfflictions.Clear();
@@ -999,22 +1024,22 @@ namespace Barotrauma
foreach (Affliction limbAffliction in limbHealth.Afflictions)
{
if (limbAffliction.Strength <= 0.0f || limbAffliction.Strength < limbAffliction.Prefab.ActivationThreshold) continue;
limbAfflictions.Add(new Pair<LimbHealth, Affliction>(limbHealth, limbAffliction));
limbAfflictions.Add((limbHealth, limbAffliction));
}
}
msg.Write((byte)limbAfflictions.Count);
foreach (var limbAffliction in limbAfflictions)
foreach (var (limbHealth, affliction) in limbAfflictions)
{
msg.WriteRangedInteger(limbHealths.IndexOf(limbAffliction.First), 0, limbHealths.Count - 1);
msg.Write(limbAffliction.Second.Prefab.UIntIdentifier);
msg.WriteRangedInteger(limbHealths.IndexOf(limbHealth), 0, limbHealths.Count - 1);
msg.Write(affliction.Prefab.UIntIdentifier);
msg.WriteRangedSingle(
MathHelper.Clamp(limbAffliction.Second.Strength, 0.0f, limbAffliction.Second.Prefab.MaxStrength),
0.0f, limbAffliction.Second.Prefab.MaxStrength, 8);
msg.Write((byte)limbAffliction.Second.Prefab.PeriodicEffects.Count());
foreach (AfflictionPrefab.PeriodicEffect periodicEffect in limbAffliction.Second.Prefab.PeriodicEffects)
MathHelper.Clamp(affliction.Strength, 0.0f, affliction.Prefab.MaxStrength),
0.0f, affliction.Prefab.MaxStrength, 8);
msg.Write((byte)affliction.Prefab.PeriodicEffects.Count());
foreach (AfflictionPrefab.PeriodicEffect periodicEffect in affliction.Prefab.PeriodicEffects)
{
msg.WriteRangedSingle(limbAffliction.Second.PeriodicEffectTimers[periodicEffect], periodicEffect.MinInterval, periodicEffect.MaxInterval, 8);
msg.WriteRangedSingle(affliction.PeriodicEffectTimers[periodicEffect], periodicEffect.MinInterval, periodicEffect.MaxInterval, 8);
}
}
}