(f2e516dfe) v0.9.3.2

This commit is contained in:
Joonas Rikkonen
2019-09-20 20:11:18 +03:00
parent 80698b58b0
commit 9aa12bcac2
144 changed files with 1653 additions and 1559 deletions
@@ -387,14 +387,17 @@ namespace Barotrauma
private void UpdateIdle(float deltaTime)
{
if (Character.Submarine == null && SimPosition.Y < ConvertUnits.ToSimUnits(Character.CharacterHealth.CrushDepth * 0.75f))
if (Character.Submarine == null &&
SimPosition.Y < ConvertUnits.ToSimUnits(Character.CharacterHealth.CrushDepth * 0.75f))
{
//steer straight up if very deep
steeringManager.SteeringManual(deltaTime, Vector2.UnitY);
return;
}
if (wallTarget != null) return;
SteerInsideLevel(deltaTime);
if (wallTarget != null) { return; }
if (SelectedAiTarget != null)
{
@@ -451,6 +454,10 @@ namespace Barotrauma
}
}
}
else
{
SteerInsideLevel(deltaTime);
}
if (escapePoint != Vector2.Zero && Vector2.DistanceSquared(Character.SimPosition, escapePoint) > 1)
{
SteeringManager.SteeringSeek(escapePoint);
@@ -1396,6 +1403,30 @@ namespace Barotrauma
AttackingLimb = null;
}
private void SteerInsideLevel(float deltaTime)
{
if (Level.Loaded == null) { return; }
Vector2 levelSimSize = new Vector2(
ConvertUnits.ToSimUnits(Level.Loaded.Size.X),
ConvertUnits.ToSimUnits(Level.Loaded.Size.Y));
float margin = 10.0f;
if (SimPosition.Y < 0.0f)
{
steeringManager.SteeringManual(deltaTime, Vector2.UnitY * MathUtils.InverseLerp(0.0f, -margin, SimPosition.Y));
}
if (SimPosition.X < 0.0f)
{
steeringManager.SteeringManual(deltaTime, Vector2.UnitX * MathUtils.InverseLerp(0.0f, -margin, SimPosition.X));
}
if (SimPosition.X > levelSimSize.X)
{
steeringManager.SteeringManual(deltaTime, Vector2.UnitX * MathUtils.InverseLerp(levelSimSize.X, levelSimSize.X + margin, SimPosition.X));
}
}
private int GetMinimumPassableHoleCount()
{
return (int)Math.Ceiling(ConvertUnits.ToDisplayUnits(colliderSize) / Structure.WallSectionSize);
@@ -81,7 +81,7 @@ namespace Barotrauma
public override void Update(float deltaTime)
{
if (DisableCrewAI || Character.IsUnconscious) return;
if (DisableCrewAI || Character.IsUnconscious || Character.Removed) { return; }
float maxDistanceToSub = 3000;
if (Character.Submarine != null || SelectedAiTarget?.Entity?.Submarine != null &&
@@ -312,8 +312,10 @@ namespace Barotrauma
Vector2 colliderBottom = character.AnimController.GetColliderBottom();
Vector2 colliderSize = collider.GetSize();
Vector2 velocity = collider.LinearVelocity;
// If the character is smaller than this, it fails to use the waypoint nodes, because they are always too high.
float minHeight = 1;
// Cannot use the head position, because not all characters have head or it can be below the total height of the character
float characterHeight = colliderSize.Y + character.AnimController.ColliderHeightFromFloor;
float characterHeight = Math.Max(colliderSize.Y + character.AnimController.ColliderHeightFromFloor, minHeight);
float horizontalDistance = Math.Abs(collider.SimPosition.X - currentPath.CurrentNode.SimPosition.X);
bool isAboveFeet = currentPath.CurrentNode.SimPosition.Y > colliderBottom.Y;
bool isNotTooHigh = currentPath.CurrentNode.SimPosition.Y < colliderBottom.Y + characterHeight;
@@ -132,7 +132,9 @@ namespace Barotrauma
{
if (Frozen) return;
if (MainLimb == null) { return; }
levitatingCollider = true;
if (!character.AllowInput)
{
levitatingCollider = false;
@@ -542,8 +544,6 @@ namespace Barotrauma
//limbs are disabled when simple physics is enabled, no need to move them
if (SimplePhysicsEnabled) { return; }
float mainLimbHeight = ColliderHeightFromFloor;
Vector2 colliderBottom = GetColliderBottom();
float movementAngle = 0.0f;
@@ -569,9 +569,9 @@ namespace Barotrauma
Vector2 pos = colliderBottom + Vector2.UnitY * TorsoPosition.Value;
if (torso != MainLimb)
{
pos.X = torso.SimPosition.X;
else
mainLimbHeight = TorsoPosition.Value;
}
torso.MoveToPos(pos, TorsoMoveForce);
torso.PullJointEnabled = true;
@@ -591,9 +591,9 @@ namespace Barotrauma
Vector2 pos = colliderBottom + Vector2.UnitY * HeadPosition.Value;
if (head != MainLimb)
{
pos.X = head.SimPosition.X;
else
mainLimbHeight = HeadPosition.Value;
}
head.MoveToPos(pos, HeadMoveForce);
head.PullJointEnabled = true;
@@ -1298,7 +1298,8 @@ namespace Barotrauma
Vector2 colliderPos = GetColliderBottom();
bool wasCritical = target.Vitality < 0.0f;
float prevVitality = target.Vitality;
bool wasCritical = prevVitality < 0.0f;
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient) //Serverside code
{
@@ -1357,7 +1358,7 @@ namespace Barotrauma
AfflictionPrefab.InternalDamage.Instantiate((CPRSettings.DamageSkillThreshold - skill) * CPRSettings.DamageSkillMultiplier,
source: character)
},
0.0f, true, 0.0f, character);
0.0f, true, 0.0f, attacker: null);
}
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient) //Serverside code
{
@@ -1389,9 +1390,12 @@ namespace Barotrauma
character.Info.IncreaseSkillLevel("medical", 0.5f, character.WorldPosition + Vector2.UnitY * 150.0f);
SteamAchievementManager.OnCharacterRevived(target, character);
lastReviveTime = (float)Timing.TotalTime;
#if SERVER
GameMain.Server?.KarmaManager?.OnCharacterHealthChanged(target, character, damage: Math.Min(prevVitality - target.Vitality, 0.0f));
#endif
//reset attacker, we don't want the character to start attacking us
//because we caused a bit of damage to them during CPR
if (target.LastAttacker == character) target.LastAttacker = null;
if (target.LastAttacker == character) { target.LastAttacker = null; }
}
}
}
@@ -1,150 +0,0 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace Barotrauma
{
partial class HumanoidAnimParams : ISerializableEntity
{
public string Name
{
get;
private set;
}
public Dictionary<string, SerializableProperty> SerializableProperties
{
get;
private set;
}
public HumanoidAnimParams(string file)
{
XDocument doc = XMLExtensions.TryLoadXml(file);
if (doc == null || doc.Root == null) return;
Name = doc.Root.Name.ToString();
SerializableProperties = SerializableProperty.DeserializeProperties(this, doc.Root);
}
[Serialize(0.3f, true), Editable]
public float GetUpSpeed
{
get;
set;
}
[Serialize(1.54f, true), Editable]
public float HeadPosition
{
get;
set;
}
[Serialize(1.15f, true), Editable]
public float TorsoPosition
{
get;
set;
}
[Serialize(0.25f, true), Editable]
public float HeadLeanAmount
{
get;
set;
}
[Serialize(0.25f, true), Editable]
public float TorsoLeanAmount
{
get;
set;
}
[Serialize(5.0f, true), Editable]
public float CycleSpeed
{
get;
set;
}
[Serialize(15.0f, true), Editable]
public float FootMoveStrength
{
get;
set;
}
[Serialize(20.0f, true), Editable]
public float FootRotateStrength
{
get;
set;
}
[Serialize("0.4,0.12", true), Editable]
public Vector2 StepSize
{
get;
set;
}
[Serialize("0.0, 0.0", true), Editable]
public Vector2 FootMoveOffset
{
get;
set;
}
[Serialize(10.0f, true), Editable]
public float LegCorrectionTorque
{
get;
set;
}
[Serialize(15.0f, true), Editable]
public float ThighCorrectionTorque
{
get;
set;
}
[Serialize("0.4, 0.15", true), Editable]
public Vector2 HandMoveAmount
{
get;
set;
}
[Serialize("-0.15, 0.0", true), Editable]
public Vector2 HandMoveOffset
{
get;
set;
}
[Serialize(0.7f, true), Editable]
public float HandMoveStrength
{
get;
set;
}
[Serialize(-1.0f, true), Editable]
public float HandClampY
{
get;
set;
}
}
}
@@ -1252,7 +1252,7 @@ namespace Barotrauma
rayEnd.Y -= Collider.height * 0.5f + Collider.radius + ColliderHeightFromFloor*1.2f;
Vector2 colliderBottomDisplay = ConvertUnits.ToDisplayUnits(GetColliderBottom());
if (!inWater && !character.IsDead && character.Stun <= 0f && levitatingCollider && Collider.LinearVelocity.Y>-ImpactTolerance)
if (!inWater && !character.IsDead && character.Stun <= 0f && levitatingCollider && Collider.LinearVelocity.Y > -ImpactTolerance)
{
float closestFraction = 1.0f;
Fixture closestFixture = null;
@@ -1484,6 +1484,9 @@ namespace Barotrauma
return (wall == null || !wall.CastShadow) && (door == null || door.IsOpen);
}
public bool HasItem(Item item, bool requireEquipped = false) =>
requireEquipped ? HasEquippedItem(item) : item.FindParentInventory(i => i.Owner == this) != null;
public bool HasEquippedItem(Item item)
{
for (int i = 0; i < Inventory.Capacity; i++)
@@ -1595,7 +1598,7 @@ namespace Barotrauma
#if CLIENT
if (Screen.Selected == GameMain.SubEditorScreen) { hidden = false; }
#endif
if (!CanInteract || hidden) return false;
if (!CanInteract || hidden || item.NonInteractable) return false;
if (item.ParentInventory != null)
{
@@ -764,13 +764,13 @@ namespace Barotrauma
public void SetSkillLevel(string skillIdentifier, float level, Vector2 worldPos)
{
if (Job == null) return;
if (Job == null) { return; }
var skill = Job.Skills.Find(s => s.Identifier == skillIdentifier);
if (skill == null)
{
Job.Skills.Add(new Skill(skillIdentifier, level));
OnSkillChanged(skillIdentifier, 0.0f, skill.Level, worldPos);
OnSkillChanged(skillIdentifier, 0.0f, level, worldPos);
}
else
{
@@ -1,141 +0,0 @@
using Microsoft.Xna.Framework;
using System;
using System.Linq;
namespace Barotrauma
{
class Affliction
{
public readonly AfflictionPrefab Prefab;
public float Strength;
public float DamagePerSecond;
public float DamagePerSecondTimer;
public float PreviousVitalityDecrease;
/// <summary>
/// Which character gave this affliction
/// </summary>
public Character Source;
public Affliction(AfflictionPrefab prefab, float strength)
{
Prefab = prefab;
Strength = strength;
}
public Affliction CreateMultiplied(float multiplier)
{
return Prefab.Instantiate(Strength * multiplier, Source);
}
public override string ToString()
{
return "Affliction (" + Prefab.Name + ")";
}
public float GetVitalityDecrease(CharacterHealth characterHealth)
{
if (Strength < Prefab.ActivationThreshold) return 0.0f;
AfflictionPrefab.Effect currentEffect = Prefab.GetActiveEffect(Strength);
if (currentEffect == null) return 0.0f;
if (currentEffect.MaxStrength - currentEffect.MinStrength <= 0.0f) return 0.0f;
float currVitalityDecrease = MathHelper.Lerp(
currentEffect.MinVitalityDecrease,
currentEffect.MaxVitalityDecrease,
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
if (currentEffect.MultiplyByMaxVitality) currVitalityDecrease *= characterHealth == null ? 100.0f : characterHealth.MaxVitality;
return currVitalityDecrease;
}
public float GetScreenDistortStrength()
{
if (Strength < Prefab.ActivationThreshold) return 0.0f;
AfflictionPrefab.Effect currentEffect = Prefab.GetActiveEffect(Strength);
if (currentEffect == null) return 0.0f;
if (currentEffect.MaxScreenDistortStrength - currentEffect.MinScreenDistortStrength <= 0.0f) return 0.0f;
return MathHelper.Lerp(
currentEffect.MinScreenDistortStrength,
currentEffect.MaxScreenDistortStrength,
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
}
public float GetRadialDistortStrength()
{
if (Strength < Prefab.ActivationThreshold) return 0.0f;
AfflictionPrefab.Effect currentEffect = Prefab.GetActiveEffect(Strength);
if (currentEffect == null) return 0.0f;
if (currentEffect.MaxRadialDistortStrength - currentEffect.MinRadialDistortStrength <= 0.0f) return 0.0f;
return MathHelper.Lerp(
currentEffect.MinRadialDistortStrength,
currentEffect.MaxRadialDistortStrength,
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
}
public float GetChromaticAberrationStrength()
{
if (Strength < Prefab.ActivationThreshold) return 0.0f;
AfflictionPrefab.Effect currentEffect = Prefab.GetActiveEffect(Strength);
if (currentEffect == null) return 0.0f;
if (currentEffect.MaxChromaticAberrationStrength - currentEffect.MinChromaticAberrationStrength <= 0.0f) return 0.0f;
return MathHelper.Lerp(
currentEffect.MinChromaticAberrationStrength,
currentEffect.MaxChromaticAberrationStrength,
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
}
public float GetScreenBlurStrength()
{
if (Strength < Prefab.ActivationThreshold) return 0.0f;
AfflictionPrefab.Effect currentEffect = Prefab.GetActiveEffect(Strength);
if (currentEffect == null) return 0.0f;
if (currentEffect.MaxScreenBlurStrength - currentEffect.MinScreenBlurStrength <= 0.0f) return 0.0f;
return MathHelper.Lerp(
currentEffect.MinScreenBlurStrength,
currentEffect.MaxScreenBlurStrength,
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
}
public void CalculateDamagePerSecond(float currentVitalityDecrease)
{
DamagePerSecond = Math.Max(DamagePerSecond, currentVitalityDecrease - PreviousVitalityDecrease);
if (DamagePerSecondTimer >= 1.0f)
{
DamagePerSecond = currentVitalityDecrease - PreviousVitalityDecrease;
PreviousVitalityDecrease = currentVitalityDecrease;
DamagePerSecondTimer = 0.0f;
}
}
public virtual void Update(CharacterHealth characterHealth, Limb targetLimb, float deltaTime)
{
AfflictionPrefab.Effect currentEffect = Prefab.GetActiveEffect(Strength);
if (currentEffect == null) return;
Strength += currentEffect.StrengthChange * deltaTime;
foreach (StatusEffect statusEffect in currentEffect.StatusEffects)
{
if (statusEffect.HasTargetType(StatusEffect.TargetType.Character))
{
statusEffect.Apply(ActionType.OnActive, deltaTime, characterHealth.Character, characterHealth.Character);
}
if (targetLimb != null && statusEffect.HasTargetType(StatusEffect.TargetType.Limb))
{
statusEffect.Apply(ActionType.OnActive, deltaTime, characterHealth.Character, targetLimb);
}
if (targetLimb != null && statusEffect.HasTargetType(StatusEffect.TargetType.AllLimbs))
{
statusEffect.Apply(ActionType.OnActive, deltaTime, targetLimb.character, targetLimb.character.AnimController.Limbs.Cast<ISerializableEntity>().ToList());
}
}
}
}
}
@@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Barotrauma
{
class AfflictionBleeding : Affliction
{
public AfflictionBleeding(AfflictionPrefab prefab, float strength) :
base(prefab, strength)
{
}
public override void Update(CharacterHealth characterHealth, Limb targetLimb, float deltaTime)
{
base.Update(characterHealth, targetLimb, deltaTime);
characterHealth.BloodlossAmount += Strength * (1.0f / 60.0f) * deltaTime;
}
}
}
@@ -1,336 +0,0 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Xml.Linq;
namespace Barotrauma
{
public static class CPRSettings
{
public static float ReviveChancePerSkill { get; private set; }
public static float ReviveChanceExponent { get; private set; }
public static float ReviveChanceMin { get; private set; }
public static float ReviveChanceMax { get; private set; }
public static float StabilizationPerSkill { get; private set; }
public static float StabilizationMin { get; private set; }
public static float StabilizationMax { get; private set; }
public static float DamageSkillThreshold { get; private set; }
public static float DamageSkillMultiplier { get; private set; }
public static void Load(XElement element)
{
ReviveChancePerSkill = Math.Max(element.GetAttributeFloat("revivechanceperskill", 0.01f), 0.0f);
ReviveChanceExponent = Math.Max(element.GetAttributeFloat("revivechanceexponent", 2.0f), 0.0f);
ReviveChanceMin = MathHelper.Clamp(element.GetAttributeFloat("revivechancemin", 0.05f), 0.0f, 1.0f);
ReviveChanceMax = MathHelper.Clamp(element.GetAttributeFloat("revivechancemax", 0.9f), ReviveChanceMin, 1.0f);
StabilizationPerSkill = Math.Max(element.GetAttributeFloat("stabilizationperskill", 0.01f), 0.0f);
StabilizationMin = MathHelper.Max(element.GetAttributeFloat("stabilizationmin", 0.05f), 0.0f);
StabilizationMax = MathHelper.Max(element.GetAttributeFloat("stabilizationmax", 2.0f), StabilizationMin);
DamageSkillThreshold = MathHelper.Clamp(element.GetAttributeFloat("damageskillthreshold", 40.0f), 0.0f, 100.0f);
DamageSkillMultiplier = MathHelper.Clamp(element.GetAttributeFloat("damageskillmultiplier", 0.1f), 0.0f, 100.0f);
}
}
class AfflictionPrefab
{
public class Effect
{
//this effect is applied when the strength is within this range
public float MinStrength, MaxStrength;
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;
public readonly bool MultiplyByMaxVitality;
public float MinScreenBlurStrength, MaxScreenBlurStrength;
public float MinScreenDistortStrength, MaxScreenDistortStrength;
public float MinRadialDistortStrength, MaxRadialDistortStrength;
public float MinChromaticAberrationStrength, MaxChromaticAberrationStrength;
public string DialogFlag;
//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);
MinScreenBlurStrength = element.GetAttributeFloat("minscreenblur", 0.0f);
MaxScreenBlurStrength = element.GetAttributeFloat("maxscreenblur", 0.0f);
MaxScreenBlurStrength = Math.Max(MinScreenBlurStrength, MaxScreenBlurStrength);
DialogFlag = element.GetAttributeString("dialogflag", "");
StrengthChange = element.GetAttributeFloat("strengthchange", 0.0f);
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "statuseffect":
StatusEffects.Add(StatusEffect.Load(subElement, parentDebugName));
break;
}
}
}
}
public static AfflictionPrefab InternalDamage;
public static AfflictionPrefab Bleeding;
public static AfflictionPrefab Burn;
public static AfflictionPrefab OxygenLow;
public static AfflictionPrefab Bloodloss;
public static AfflictionPrefab Pressure;
public static AfflictionPrefab Stun;
public static AfflictionPrefab Husk;
public static List<AfflictionPrefab> List = new List<AfflictionPrefab>();
//Arbitrary string that is used to identify the type of the affliction.
//Afflictions with the same type stack up, and items may be configured to cure specific types of afflictions.
public readonly string AfflictionType;
//Does the affliction affect a specific limb or the whole character
public readonly bool LimbSpecific;
//If not a limb-specific affliction, which limb is the indicator shown on in the health menu
//(e.g. mental health problems on head, lack of oxygen on torso...)
public readonly LimbType IndicatorLimb;
public readonly string Identifier;
public readonly string Name, Description;
public readonly string CauseOfDeathDescription, SelfCauseOfDeathDescription;
//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
public readonly float ShowIconThreshold = 0.0f;
public readonly float MaxStrength = 100.0f;
public float BurnOverlayAlpha;
public float DamageOverlayAlpha;
//steam achievement given when the affliction is removed from the controlled character
public readonly string AchievementOnRemoved;
public readonly Sprite Icon;
public readonly Color IconColor;
private List<Effect> effects = new List<Effect>();
private Dictionary<string, float> treatmentSuitability = new Dictionary<string, float>();
private readonly string typeName;
private readonly ConstructorInfo constructor;
public Dictionary<string, float> TreatmentSuitability
{
get { return treatmentSuitability; }
}
public static void LoadAll(IEnumerable<string> filePaths)
{
foreach (string filePath in filePaths)
{
XDocument doc = XMLExtensions.TryLoadXml(filePath);
if (doc == null || doc.Root == null) continue;
foreach (XElement element in doc.Root.Elements())
{
switch (element.Name.ToString().ToLowerInvariant())
{
case "internaldamage":
List.Add(InternalDamage = new AfflictionPrefab(element, typeof(Affliction)));
break;
case "bleeding":
List.Add(Bleeding = new AfflictionPrefab(element, typeof(AfflictionBleeding)));
break;
case "burn":
List.Add(Burn = new AfflictionPrefab(element, typeof(Affliction)));
break;
case "oxygenlow":
List.Add(OxygenLow = new AfflictionPrefab(element, typeof(Affliction)));
break;
case "bloodloss":
List.Add(Bloodloss = new AfflictionPrefab(element, typeof(Affliction)));
break;
case "pressure":
List.Add(Pressure = new AfflictionPrefab(element, typeof(Affliction)));
break;
case "stun":
List.Add(Stun = new AfflictionPrefab(element, typeof(Affliction)));
break;
case "husk":
case "afflictionhusk":
List.Add(Husk = new AfflictionPrefab(element, typeof(AfflictionHusk)));
break;
case "cprsettings":
CPRSettings.Load(element);
break;
default:
List.Add(new AfflictionPrefab(element));
break;
}
}
}
if (InternalDamage == null) DebugConsole.ThrowError("Affliction \"Internal Damage\" not defined in the affliction prefabs.");
if (Bleeding == null) DebugConsole.ThrowError("Affliction \"Bleeding\" not defined in the affliction prefabs.");
if (Burn == null) DebugConsole.ThrowError("Affliction \"Burn\" not defined in the affliction prefabs.");
if (OxygenLow == null) DebugConsole.ThrowError("Affliction \"OxygenLow\" not defined in the affliction prefabs.");
if (Bloodloss == null) DebugConsole.ThrowError("Affliction \"Bloodloss\" not defined in the affliction prefabs.");
if (Pressure == null) DebugConsole.ThrowError("Affliction \"Pressure\" not defined in the affliction prefabs.");
if (Stun == null) DebugConsole.ThrowError("Affliction \"Stun\" not defined in the affliction prefabs.");
if (Husk == null) DebugConsole.ThrowError("Affliction \"Husk\" not defined in the affliction prefabs.");
}
public AfflictionPrefab(XElement element, Type type = null)
{
typeName = type == null ? element.Name.ToString() : type.Name;
Identifier = element.GetAttributeString("identifier", "");
AfflictionType = element.GetAttributeString("type", "");
Name = TextManager.Get("AfflictionName." + Identifier, true) ?? element.GetAttributeString("name", "");
Description = TextManager.Get("AfflictionDescription." + Identifier, true) ?? element.GetAttributeString("description", "");
LimbSpecific = element.GetAttributeBool("limbspecific", false);
if (!LimbSpecific)
{
string indicatorLimbName = element.GetAttributeString("indicatorlimb", "Torso");
if (!Enum.TryParse(indicatorLimbName, out IndicatorLimb))
{
DebugConsole.ThrowError("Error in affliction prefab " + Name + " - limb type \"" + indicatorLimbName + "\" not found.");
}
}
ActivationThreshold = element.GetAttributeFloat("activationthreshold", 0.0f);
ShowIconThreshold = element.GetAttributeFloat("showiconthreshold", ActivationThreshold);
MaxStrength = element.GetAttributeFloat("maxstrength", 100.0f);
DamageOverlayAlpha = element.GetAttributeFloat("damageoverlayalpha", 0.0f);
BurnOverlayAlpha = element.GetAttributeFloat("burnoverlayalpha", 0.0f);
CauseOfDeathDescription = TextManager.Get("AfflictionCauseOfDeath." + Identifier, true) ?? element.GetAttributeString("causeofdeathdescription", "");
SelfCauseOfDeathDescription = TextManager.Get("AfflictionCauseOfDeathSelf." + Identifier, true) ?? element.GetAttributeString("selfcauseofdeathdescription", "");
AchievementOnRemoved = element.GetAttributeString("achievementonremoved", "");
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "icon":
Icon = new Sprite(subElement);
IconColor = subElement.GetAttributeColor("color", Color.White);
break;
case "effect":
effects.Add(new Effect(subElement, Name));
break;
}
}
try
{
if (type == null)
{
type = Type.GetType("Barotrauma." + typeName, true, true);
if (type == null)
{
DebugConsole.ThrowError("Could not find an affliction class of the type \"" + typeName + "\".");
return;
}
}
}
catch
{
DebugConsole.ThrowError("Could not find an affliction class of the type \"" + typeName + "\".");
return;
}
constructor = type.GetConstructor(new[] { typeof(AfflictionPrefab), typeof(float) });
}
public override string ToString()
{
return "AfflictionPrefab (" + Name + ")";
}
public Affliction Instantiate(float strength, Character source = null)
{
object instance = null;
try
{
instance = constructor.Invoke(new object[] { this, strength });
}
catch (Exception ex)
{
DebugConsole.ThrowError(ex.InnerException != null ? ex.InnerException.ToString() : ex.ToString());
}
Affliction affliction = instance as Affliction;
affliction.Source = source;
return affliction;
}
public Effect GetActiveEffect(float currentStrength)
{
foreach (Effect effect in effects)
{
if (currentStrength > effect.MinStrength && currentStrength <= effect.MaxStrength) return effect;
}
//if above the strength range of all effects, use the highest strength effect
Effect strongestEffect = null;
float largestStrength = currentStrength;
foreach (Effect effect in effects)
{
if (currentStrength > effect.MaxStrength &&
(strongestEffect == null || effect.MaxStrength > largestStrength))
{
strongestEffect = effect;
largestStrength = effect.MaxStrength;
}
}
return strongestEffect;
}
public float GetTreatmentSuitability(Item item)
{
if (item == null || !treatmentSuitability.ContainsKey(item.Prefab.Identifier.ToLowerInvariant()))
{
return 0.0f;
}
return treatmentSuitability[item.Prefab.Identifier.ToLowerInvariant()];
}
}
}
@@ -1,27 +0,0 @@
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Barotrauma.Extensions;
using System.Xml.Linq;
using System;
namespace Barotrauma
{
partial class AfflictionPsychosis : Affliction
{
public AfflictionPsychosis(AfflictionPrefab prefab, float strength) : base(prefab, strength)
{
}
public override void Update(CharacterHealth characterHealth, Limb targetLimb, float deltaTime)
{
base.Update(characterHealth, targetLimb, deltaTime);
UpdateProjSpecific(characterHealth, targetLimb, deltaTime);
}
partial void UpdateProjSpecific(CharacterHealth characterHealth, Limb targetLimb, float deltaTime);
}
}
@@ -739,7 +739,7 @@ namespace Barotrauma
msg.Write((byte)activeAfflictions.Count);
foreach (Affliction affliction in activeAfflictions)
{
msg.WriteRangedIntegerDeprecated(0, AfflictionPrefab.List.Count - 1, AfflictionPrefab.List.IndexOf(affliction.Prefab));
msg.WriteRangedInteger(AfflictionPrefab.List.IndexOf(affliction.Prefab), 0, AfflictionPrefab.List.Count - 1);
msg.WriteRangedSingle(
MathHelper.Clamp(affliction.Strength, 0.0f, affliction.Prefab.MaxStrength),
0.0f, affliction.Prefab.MaxStrength, 8);
@@ -758,8 +758,8 @@ namespace Barotrauma
msg.Write((byte)limbAfflictions.Count);
foreach (var limbAffliction in limbAfflictions)
{
msg.WriteRangedIntegerDeprecated(0, limbHealths.Count - 1, limbHealths.IndexOf(limbAffliction.First));
msg.WriteRangedIntegerDeprecated(0, AfflictionPrefab.List.Count - 1, AfflictionPrefab.List.IndexOf(limbAffliction.Second.Prefab));
msg.WriteRangedInteger(limbHealths.IndexOf(limbAffliction.First), 0, limbHealths.Count - 1);
msg.WriteRangedInteger(AfflictionPrefab.List.IndexOf(limbAffliction.Second.Prefab), 0, AfflictionPrefab.List.Count - 1);
msg.WriteRangedSingle(
MathHelper.Clamp(limbAffliction.Second.Strength, 0.0f, limbAffliction.Second.Prefab.MaxStrength),
0.0f, limbAffliction.Second.Prefab.MaxStrength, 8);
@@ -90,6 +90,7 @@ namespace Barotrauma.Items.Components
item.body.FarseerBody.CollisionCategories = Physics.CollisionProjectile;
item.body.FarseerBody.CollidesWith = Physics.CollisionCharacter | Physics.CollisionWall;
item.body.FarseerBody.OnCollision += OnCollision;
item.body.FarseerBody.IsBullet = true;
if (!character.AnimController.InWater)
{
@@ -207,9 +208,9 @@ namespace Barotrauma.Items.Components
private void RestoreCollision()
{
item.body.FarseerBody.OnCollision -= OnCollision;
item.body.CollisionCategories = Physics.CollisionItem;
item.body.CollidesWith = Physics.CollisionWall;
item.body.FarseerBody.IsBullet = false;
}
@@ -132,7 +132,7 @@ namespace Barotrauma.Items.Components
return false;
}
if (character.AnimController.InWater)
if (item.InWater)
{
if (UsableIn == UseEnvironment.Air)
{
@@ -160,7 +160,8 @@ namespace Barotrauma.Items.Components
}
else
{
rayStart = ConvertUnits.ToSimUnits(item.WorldPosition);
rayStart = Submarine.LastPickedPosition + Submarine.LastPickedNormal * 0.1f;
if (item.Submarine != null) { rayStart += item.Submarine.SimPosition; }
}
Vector2 rayEnd = rayStart +
@@ -201,12 +202,12 @@ namespace Barotrauma.Items.Components
Repair(rayStart - character.Submarine.SimPosition, rayEnd - character.Submarine.SimPosition, deltaTime, character, degreeOfSuccess, ignoredBodies);
}
UseProjSpecific(deltaTime);
UseProjSpecific(deltaTime, rayStart);
return true;
}
partial void UseProjSpecific(float deltaTime);
partial void UseProjSpecific(float deltaTime, Vector2 raystart);
private readonly HashSet<Character> hitCharacters = new HashSet<Character>();
private readonly List<FireSource> fireSourcesInRange = new List<FireSource>();
@@ -1,4 +1,5 @@
using FarseerPhysics;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
@@ -19,7 +20,7 @@ namespace Barotrauma.Items.Components
}
}
partial class Controller : ItemComponent
partial class Controller : ItemComponent, IServerSerializable
{
//where the limbs of the user should be positioned when using the controller
private List<LimbPos> limbPositions;
@@ -270,17 +271,21 @@ namespace Barotrauma.Items.Components
{
if (IsToggle)
{
state = !state;
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
{
state = !state;
#if SERVER
item.CreateServerEvent(this);
#endif
}
}
else
{
item.SendSignal(0, "1", "signal_out", picker);
}
#if CLIENT
PlaySound(ActionType.OnUse, item.WorldPosition, picker);
#endif
return true;
}
@@ -273,14 +273,18 @@ namespace Barotrauma.Items.Components
{
if (connection.Name == "set_rate")
{
float tempSpeed;
if (float.TryParse(signal, NumberStyles.Any, CultureInfo.InvariantCulture, out tempSpeed))
if (float.TryParse(signal, NumberStyles.Any, CultureInfo.InvariantCulture, out float tempSpeed))
{
if (!MathUtils.IsValid(tempSpeed)) return;
RechargeSpeed = MathHelper.Clamp(tempSpeed / 100.0f, 0.0f, 1.0f) * MaxRechargeSpeed;
if (!MathUtils.IsValid(tempSpeed)) { return; }
float rechargeRate = MathHelper.Clamp(tempSpeed / 100.0f, 0.0f, 1.0f);
RechargeSpeed = rechargeRate * MaxRechargeSpeed;
#if CLIENT
rechargeSpeedSlider.BarScroll = rechargeRate;
#endif
}
}
if (!connection.IsPower) return;
if (!connection.IsPower) { return; }
if (connection.Name == "power_in")
{
@@ -146,6 +146,10 @@ namespace Barotrauma.Items.Components
currentFixerAction = FixActions.None;
#if SERVER
item.CreateServerEvent(this);
#endif
#if CLIENT
repairSoundChannel?.FadeOutAndDispose();
repairSoundChannel = null;
#endif
return true;
}
@@ -221,8 +225,8 @@ namespace Barotrauma.Items.Components
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
float successFactor = requiredSkills.Count == 0 ? 1.0f : 0.0f;
float successFactor = requiredSkills.Count == 0 ? 1.0f : DegreeOfSuccess(CurrentFixer, requiredSkills);
//item must have been below the repair threshold for the player to get an achievement or XP for repairing it
if (item.ConditionPercentage < ShowRepairUIThreshold)
{
@@ -122,22 +122,7 @@ namespace Barotrauma.Items.Components
public override void Update(float deltaTime, Camera cam)
{
#if CLIENT
foreach (Wire wire in DisconnectedWires)
{
if (Rand.Range(0.0f, 500.0f) < 1.0f)
{
SoundPlayer.PlaySound("zap", item.WorldPosition, hullGuess: item.CurrentHull);
Vector2 baseVel = new Vector2(0.0f, -100.0f);
for (int i = 0; i < 5; i++)
{
var particle = GameMain.ParticleManager.CreateParticle("spark", item.WorldPosition,
baseVel + Rand.Vector(100.0f), 0.0f, item.CurrentHull);
if (particle != null) { particle.Size *= Rand.Range(0.5f, 1.0f); }
}
}
}
#endif
UpdateProjSpecific(deltaTime);
if (user == null || user.SelectedConstruction != item)
{
@@ -150,6 +135,8 @@ namespace Barotrauma.Items.Components
user.AnimController.UpdateUseItem(true, item.WorldPosition + new Vector2(0.0f, 100.0f) * (((float)Timing.TotalTime / 10.0f) % 0.1f));
}
partial void UpdateProjSpecific(float deltaTime);
public override bool Select(Character picker)
{
//attaching wires to items with a body is not allowed
@@ -260,8 +247,14 @@ namespace Barotrauma.Items.Components
}
}
}
#if CLIENT
rewireSoundChannel?.FadeOutAndDispose();
rewireSoundChannel = null;
#endif
}
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
{
foreach (Connection connection in Connections)
@@ -160,6 +160,14 @@ namespace Barotrauma.Items.Components
item.AddTag("light");
}
#if CLIENT
public override void OnScaleChanged()
{
light.SpriteScale = Vector2.One * item.Scale;
light.Position = ParentBody != null ? ParentBody.Position : item.Position;
}
#endif
public override void OnItemLoaded()
{
base.OnItemLoaded();
@@ -175,7 +183,6 @@ namespace Barotrauma.Items.Components
UpdateOnActiveEffects(deltaTime);
#if CLIENT
light.SpriteScale = Vector2.One * item.Scale;
light.ParentSub = item.Submarine;
if (item.Container != null)
{
@@ -336,30 +336,39 @@ namespace Barotrauma
}
}
public Item FindItemByTag(string tag)
public Item FindItem(Func<Item, bool> predicate, bool recursive)
{
if (tag == null) return null;
return Items.FirstOrDefault(i => i != null && i.HasTag(tag));
Item match = Items.FirstOrDefault(predicate);
if (match == null && recursive)
{
foreach (var item in Items)
{
if (item == null) { continue; }
if (item.OwnInventory != null)
{
match = item.OwnInventory.FindItem(predicate, true);
if (match != null)
{
return match;
}
}
}
}
return match;
}
public Item FindItemByIdentifier(string identifier)
public Item FindItemByTag(string tag, bool recursive = false)
{
if (tag == null) { return null; }
return FindItem(i => i != null && i.HasTag(tag), recursive);
}
public Item FindItemByIdentifier(string identifier, bool recursive = false)
{
if (identifier == null) return null;
return Items.FirstOrDefault(i => i != null && i.Prefab.Identifier == identifier);
return FindItem(i => i != null && i.Prefab.Identifier == identifier, recursive);
}
/*public Item FindItem(string[] itemNames)
{
if (itemNames == null) return null;
foreach (string itemName in itemNames)
{
var item = FindItem(itemName);
if (item != null) return item;
}
return null;
}*/
public virtual void RemoveItem(Item item)
{
if (item == null) return;
@@ -376,6 +385,7 @@ namespace Barotrauma
public void SharedWrite(IWriteMessage msg, object[] extraData = null)
{
msg.Write((byte)capacity);
for (int i = 0; i < capacity; i++)
{
msg.Write((ushort)(Items[i] == null ? 0 : Items[i].ID));
@@ -126,24 +126,6 @@ namespace Barotrauma
}
}
public delegate bool InventoryFilter(Inventory inventory);
public Inventory FindParentInventory(InventoryFilter filter)
{
if (parentInventory != null)
{
if (filter(parentInventory))
{
return parentInventory;
}
var owner = parentInventory.Owner as Item;
if (owner != null)
{
return owner.FindParentInventory(filter);
}
}
return null;
}
private Item container;
public Item Container
{
@@ -177,6 +159,13 @@ namespace Barotrauma
set;
}
[Editable, Serialize(false, true)]
public bool NonInteractable
{
get;
set;
}
public float ImpactTolerance
{
get { return Prefab.ImpactTolerance; }
@@ -398,6 +387,7 @@ namespace Barotrauma
}
else if (!MathUtils.NearlyEqual(lastSentCondition, condition) && (condition <= 0.0f || condition >= Prefab.Health))
{
sendConditionUpdateTimer = 0.0f;
conditionUpdatePending = true;
}
}
@@ -955,7 +945,6 @@ namespace Barotrauma
return CurrentHull;
}
CurrentHull = Hull.FindHull(WorldPosition, CurrentHull);
if (body != null && body.Enabled)
{
@@ -978,7 +967,23 @@ namespace Barotrauma
return rootContainer;
}
public Inventory FindParentInventory(Func<Inventory, bool> predicate)
{
if (parentInventory != null)
{
if (predicate(parentInventory))
{
return parentInventory;
}
if (parentInventory.Owner is Item owner)
{
return owner.FindParentInventory(predicate);
}
}
return null;
}
public void SetContainedItemPositions()
{
foreach (ItemComponent component in components)
@@ -1137,6 +1142,17 @@ namespace Barotrauma
return CurrentHull.WaterVolume > 0.0f && Position.Y < surfaceY;
}
public void SendPendingNetworkUpdates()
{
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsServer) { return; }
if (conditionUpdatePending)
{
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });
lastSentCondition = condition;
sendConditionUpdateTimer = NetConfig.ItemConditionUpdateInterval;
conditionUpdatePending = false;
}
}
public override void Update(float deltaTime, Camera cam)
{
@@ -1153,16 +1169,10 @@ namespace Barotrauma
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
{
sendConditionUpdateTimer -= deltaTime;
if (conditionUpdatePending)
if (conditionUpdatePending && sendConditionUpdateTimer <= 0.0f)
{
if (sendConditionUpdateTimer <= 0.0f)
{
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });
lastSentCondition = condition;
sendConditionUpdateTimer = NetConfig.ItemConditionUpdateInterval;
conditionUpdatePending = false;
}
}
SendPendingNetworkUpdates();
}
}
ApplyStatusEffects(ActionType.Always, deltaTime, null);
@@ -1878,7 +1888,7 @@ namespace Barotrauma
var propertyOwner = allProperties.Find(p => p.Second == property);
if (allProperties.Count > 1)
{
msg.WriteRangedIntegerDeprecated(0, allProperties.Count - 1, allProperties.FindIndex(p => p.Second == property));
msg.WriteRangedInteger(allProperties.FindIndex(p => p.Second == property), 0, allProperties.Count - 1);
}
object value = property.GetValue(propertyOwner.First);
@@ -2141,7 +2151,8 @@ namespace Barotrauma
if (element.GetAttributeBool("flippedx", false)) item.FlipX(false);
if (element.GetAttributeBool("flippedy", false)) item.FlipY(false);
item.condition = element.GetAttributeFloat("condition", item.Prefab.Health);
float condition = element.GetAttributeFloat("condition", item.MaxCondition);
item.condition = MathHelper.Clamp(condition, 0, item.MaxCondition);
item.lastSentCondition = item.condition;
item.SetActiveSprite();
@@ -1,6 +1,7 @@
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
namespace Barotrauma
@@ -92,10 +93,10 @@ namespace Barotrauma
{
if (!Item.ItemList.Contains(container.Item))
{
string errorMsg = "Attempted to create a network event for an item (" + container.Item.Name + ") that hasn't been fully initialized yet.";
string errorMsg = "Attempted to create a network event for an item (" + container.Item.Name + ") that hasn't been fully initialized yet.\n" + Environment.StackTrace;
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce(
"ItemInventory.CreateServerEvent:EventForUninitializedItem" + container.Item.Name + container.Item.ID,
"ItemInventory.CreateServerEvent:EventForUninitializedItem" + container.Item.Name + container.Item.ID,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
return;
}
@@ -12,10 +12,7 @@ namespace Barotrauma
{
private readonly XElement configElement;
private readonly string configPath;
[Serialize(false, false)]
public bool HideInMenus { get; set; }
public List<Pair<MapEntityPrefab, Rectangle>> DisplayEntities
{
get;
@@ -409,7 +409,7 @@ namespace Barotrauma
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
{
LevelObject obj = extraData[0] as LevelObject;
msg.WriteRangedIntegerDeprecated(0, objects.Count, objects.IndexOf(obj));
msg.WriteRangedInteger(objects.IndexOf(obj), 0, objects.Count);
obj.ServerWrite(msg, c);
}
}
@@ -344,7 +344,11 @@ namespace Barotrauma
structure.Update(deltaTime, cam);
}
foreach (Gap gap in Gap.GapList)
//update gaps in random order, because otherwise in rooms with multiple gaps
//the water/air will always tend to flow through the first gap in the list,
//which may lead to weird behavior like water draining down only through
//one gap in a room even if there are several
foreach (Gap gap in Gap.GapList.OrderBy(g => Rand.Int(int.MaxValue)))
{
gap.Update(deltaTime, cam);
}
@@ -562,7 +566,7 @@ namespace Barotrauma
}
}
[Serialize(1f, true), Editable(0.1f, 10f, DecimalCount = 3, ValueStep = 0.1f)]
[Serialize(1f, true), Editable(0.01f, 10f, DecimalCount = 3, ValueStep = 0.1f)]
public virtual float Scale { get; set; } = 1;
#endregion
}
@@ -77,7 +77,10 @@ namespace Barotrauma
get;
protected set;
}
[Serialize(false, false)]
public bool HideInMenus { get; set; }
[Serialize(false, false)]
public bool Linkable
{
@@ -8,6 +8,8 @@ namespace Barotrauma
{
public class Md5Hash
{
private static Regex removeWhitespaceRegex = new Regex(@"\s+", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public string Hash { get; private set; }
public string ShortHash { get; private set; }
@@ -34,14 +36,13 @@ namespace Barotrauma
public Md5Hash(XDocument doc)
{
if (doc == null) return;
string docString = Regex.Replace(doc.ToString(), @"\s+", "");
if (doc == null) { return; }
string docString = removeWhitespaceRegex.Replace(doc.ToString(), "");
byte[] inputBytes = Encoding.ASCII.GetBytes(docString);
Hash = CalculateHash(inputBytes);
Hash = CalculateHash(inputBytes);
ShortHash = GetShortHash(Hash);
}
@@ -1296,7 +1296,6 @@ namespace Barotrauma
public override void Update(float deltaTime, Camera cam)
{
base.Update(deltaTime, cam);
if (aiTarget != null)
{
aiTarget.SightRange = Submarine == null ? aiTarget.MinSightRange : Submarine.Velocity.Length() / 2 * aiTarget.MaxSightRange;
@@ -10,6 +10,7 @@ using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using Voronoi2;
@@ -82,6 +83,7 @@ namespace Barotrauma
private static float lastPickedFraction;
private static Vector2 lastPickedNormal;
private Task hashTask;
private Md5Hash hash;
private string filePath;
@@ -165,10 +167,12 @@ namespace Barotrauma
{
get
{
if (hash != null) return hash;
XDocument doc = OpenFile(filePath);
hash = new Md5Hash(doc);
if (hash == null)
{
XDocument doc = OpenFile(filePath);
StartHashDocTask(doc);
hashTask.Wait();
}
return hash;
}
@@ -316,7 +320,7 @@ namespace Barotrauma
DebugConsole.ThrowError("Error loading submarine " + filePath + "!", e);
}
if (hash != "")
if (!string.IsNullOrWhiteSpace(hash))
{
this.hash = new Md5Hash(hash);
}
@@ -341,6 +345,11 @@ namespace Barotrauma
if (doc != null && doc.Root != null)
{
if (string.IsNullOrWhiteSpace(hash))
{
StartHashDocTask(doc);
}
displayName = TextManager.Get("Submarine.Name." + name, true);
if (displayName == null || displayName.Length == 0) displayName = name;
@@ -397,6 +406,18 @@ namespace Barotrauma
FreeID();
}
public void StartHashDocTask(XDocument doc)
{
if (hash != null) { return; }
if (hashTask != null) { return; }
hashTask = new Task(() =>
{
hash = new Md5Hash(doc);
});
hashTask.Start();
}
public bool HasTag(SubmarineTag tag)
{
return tags.HasFlag(tag);
@@ -18,7 +18,7 @@ namespace Barotrauma.Networking
{
const string SavePath = "Data/bannedplayers.txt";
private List<BannedPlayer> bannedPlayers;
private readonly List<BannedPlayer> bannedPlayers;
public IEnumerable<string> BannedNames
{
@@ -233,11 +233,10 @@ namespace Barotrauma.Networking
public static bool CanUseRadio(Character sender, out WifiComponent radio)
{
radio = null;
if (sender == null) { return false; }
var senderItem = sender.Inventory.Items.FirstOrDefault(i => i?.GetComponent<WifiComponent>() != null);
if (senderItem == null) { return false; }
radio = senderItem.GetComponent<WifiComponent>();
return sender.HasEquippedItem(senderItem) && radio.CanTransmit();
if (sender?.Inventory == null || sender.Removed) { return false; }
radio = sender.Inventory.Items.FirstOrDefault(i => i?.GetComponent<WifiComponent>() != null)?.GetComponent<WifiComponent>();
if (radio?.Item == null) { return false; }
return sender.HasEquippedItem(radio.Item) && radio.CanTransmit();
}
}
}
@@ -69,11 +69,12 @@ namespace Barotrauma.Networking
public static void LoadAll(string file)
{
if (!File.Exists(file)) return;
if (!File.Exists(file)) { return; }
XDocument doc = XMLExtensions.TryLoadXml(file);
if (doc == null || doc.Root == null) return;
if (doc == null || doc.Root == null) { return; }
List.Clear();
foreach (XElement element in doc.Root.Elements())
{
List.Add(new PermissionPreset(element));
@@ -176,9 +176,7 @@ namespace Barotrauma
var spawnedEntity = entitySpawnInfo.Spawn();
if (spawnedEntity != null)
{
#if SERVER
CreateNetworkEvent(spawnedEntity, false);
#endif
CreateNetworkEventProjSpecific(spawnedEntity, false);
if (spawnedEntity is Item)
{
((Item)spawnedEntity).Condition = ((ItemSpawnInfo)entitySpawnInfo).Condition;
@@ -189,18 +187,17 @@ namespace Barotrauma
while (removeQueue.Count > 0)
{
var removedEntity = removeQueue.Dequeue();
#if SERVER
if (GameMain.Server != null)
if (removedEntity is Item item)
{
CreateNetworkEvent(removedEntity, true);
item.SendPendingNetworkUpdates();
}
#endif
CreateNetworkEventProjSpecific(removedEntity, true);
removedEntity.Remove();
}
}
partial void CreateNetworkEventProjSpecific(Entity entity, bool remove);
public void Reset()
{
removeQueue.Clear();
@@ -15,6 +15,9 @@ namespace Barotrauma
public Dictionary<string, SerializableProperty> SerializableProperties { get; private set; }
[Serialize(true, true)]
public bool ResetKarmaBetweenRounds { get; set; }
[Serialize(0.1f, true)]
public float KarmaDecay { get; set; }
@@ -75,13 +78,16 @@ namespace Barotrauma
[Serialize(1.0f, true)]
public float KickBanThreshold { get; set; }
[Serialize(0, true)]
public int KicksBeforeBan { get; set; }
[Serialize(10.0f, true)]
public float KarmaNotificationInterval { get; set; }
[Serialize(120.0f, true)]
public float AllowedRetaliationTime { get; set; }
private readonly AfflictionPrefab herpesAffliction;
public Dictionary<string, XElement> Presets = new Dictionary<string, XElement>();
@@ -17,7 +17,6 @@ namespace Barotrauma.Networking
void Write(Double val);
void WriteVariableUInt32(UInt32 val);
void Write(string val);
void WriteRangedIntegerDeprecated(int min, int max, int val); //TODO: remove this, val should be first parameter >:(
void WriteRangedInteger(int val, int min, int max);
void WriteRangedSingle(Single val, Single min, Single max, int bitCount);
void Write(byte[] val, int startIndex, int length);
@@ -493,11 +493,6 @@ namespace Barotrauma.Networking
MsgWriter.Write(ref buf, ref seekPos, val);
}
public void WriteRangedIntegerDeprecated(int min, int max, int val)
{
MsgWriter.WriteRangedInteger(ref buf, ref seekPos, val, min, max);
}
public void WriteRangedInteger(int val, int min, int max)
{
MsgWriter.WriteRangedInteger(ref buf, ref seekPos, val, min, max);
@@ -547,7 +542,7 @@ namespace Barotrauma.Networking
if (compressedBuf.Length > outBuf.Length) { Array.Resize(ref outBuf, compressedBuf.Length); }
Array.Copy(compressedBuf, outBuf, compressedBuf.Length);
length = compressedBuf.Length;
DebugConsole.NewMessage("Compressed message: " + LengthBytes + " to " + length);
DebugConsole.Log("Compressed message: " + LengthBytes + " to " + length);
}
}
}
@@ -632,7 +627,7 @@ namespace Barotrauma.Networking
buf = new byte[decompressedData.Length];
Array.Copy(decompressedData, 0, buf, 0, decompressedData.Length);
lengthBits = decompressedData.Length * 8;
DebugConsole.NewMessage("Decompressing message: " + inLength + " to " + LengthBytes);
DebugConsole.Log("Decompressing message: " + inLength + " to " + LengthBytes);
}
else
{
@@ -847,10 +842,6 @@ namespace Barotrauma.Networking
MsgWriter.Write(ref buf, ref seekPos, val);
}
public void WriteRangedIntegerDeprecated(int min, int max, int val)
{
MsgWriter.WriteRangedInteger(ref buf, ref seekPos, val, min, max);
}
public void WriteRangedInteger(int val, int min, int max)
{
@@ -13,6 +13,8 @@ namespace Barotrauma.Networking
public abstract class NetworkConnection
{
public const double TimeoutThreshold = 60.0; //full minute for timeout because loading screens can take quite a while
public string Name;
public UInt64 SteamID
@@ -23,7 +23,7 @@ namespace Barotrauma.Networking
public void Heartbeat()
{
Timeout = 20.0;
Timeout = NetworkConnection.TimeoutThreshold;
}
}
}
@@ -1,60 +0,0 @@
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma.Networking
{
partial class ServerInfo
{
public string IP;
public string Port;
public string ServerName;
public string ServerMessage;
public bool GameStarted;
public int PlayerCount;
public int MaxPlayers;
public bool HasPassword;
public bool PingChecked;
public int Ping = -1;
//null value means that the value isn't known (the server may be using
//an old version of the game that didn't report these values or the FetchRules query to Steam may not have finished yet)
public bool? UsingWhiteList;
public SelectionMode? ModeSelectionMode;
public SelectionMode? SubSelectionMode;
public bool? AllowSpectating;
public bool? AllowRespawn;
public YesNoMaybe? TraitorsEnabled;
public string GameMode;
public bool? RespondedToSteamQuery = null;
public string GameVersion;
public List<string> ContentPackageNames
{
get;
private set;
} = new List<string>();
public List<string> ContentPackageHashes
{
get;
private set;
} = new List<string>();
public List<string> ContentPackageWorkshopUrls
{
get;
private set;
} = new List<string>();
public bool ContentPackagesMatch(IEnumerable<ContentPackage> myContentPackages)
{
return ContentPackagesMatch(myContentPackages.Select(cp => cp.MD5hash.Hash));
}
public bool ContentPackagesMatch(IEnumerable<string> myContentPackageHashes)
{
HashSet<string> contentPackageHashes = new HashSet<string>(ContentPackageHashes);
return contentPackageHashes.SetEquals(myContentPackageHashes);
}
}
}
@@ -20,7 +20,8 @@ namespace Barotrauma
SpeciesName,
HasTag,
HasStatusTag,
Affliction
Affliction,
EntityType
}
public enum Comparison
@@ -161,15 +162,18 @@ namespace Barotrauma
{
case ConditionType.PropertyValue:
SerializableProperty property;
if (target?.SerializableProperties == null) { return Operator == OperatorType.NotEquals; }
if (target.SerializableProperties.TryGetValue(AttributeName, out property))
{
return Matches(target, property);
}
return false;
case ConditionType.Name:
if (target == null) { return Operator == OperatorType.NotEquals; }
return (Operator == OperatorType.Equals) == (target.Name == valStr);
case ConditionType.HasTag:
{
if (target == null) { return Operator == OperatorType.NotEquals; }
string[] readTags = valStr.Split(',');
int matches = 0;
foreach (string tag in readTags)
@@ -179,6 +183,8 @@ namespace Barotrauma
return Operator == OperatorType.Equals ? matches >= readTags.Length : matches <= 0;
}
case ConditionType.HasStatusTag:
if (target == null) { return Operator == OperatorType.NotEquals; }
List<DurationListElement> durations = StatusEffect.DurationList.FindAll(d => d.Targets.Contains(target));
List<DelayedListElement> delays = DelayedEffect.DelayList.FindAll(d => d.Targets.Contains(target));
@@ -218,10 +224,29 @@ namespace Barotrauma
}
return success;
case ConditionType.SpeciesName:
if (target == null) { return Operator == OperatorType.NotEquals; }
Character targetCharacter = target as Character;
if (targetCharacter == null) return false;
if (targetCharacter == null) { return false; }
return (Operator == OperatorType.Equals) == (targetCharacter.SpeciesName == valStr);
case ConditionType.EntityType:
switch (valStr)
{
case "character":
case "Character":
return (Operator == OperatorType.Equals) == target is Character;
case "item":
case "Item":
return (Operator == OperatorType.Equals) == target is Item;
case "structure":
case "Structure":
return (Operator == OperatorType.Equals) == target is Structure;
case "null":
return (Operator == OperatorType.Equals) == (target == null);
default:
return false;
}
case ConditionType.Affliction:
if (target == null) { return Operator == OperatorType.NotEquals; }
if (target is Character targetChar)
{
var health = targetChar.CharacterHealth;
@@ -13,6 +13,7 @@ namespace Barotrauma
public Entity Entity;
public List<ISerializableEntity> Targets;
public float Timer;
public Character User;
}
partial class StatusEffect
@@ -432,7 +433,6 @@ namespace Barotrauma
case PropertyConditional.Comparison.Or:
foreach (ISerializableEntity target in targets)
{
if (target == null || target.SerializableProperties == null) { continue; }
foreach (PropertyConditional pc in propertyConditionals)
{
if (!string.IsNullOrEmpty(pc.TargetItemComponentName))
@@ -449,7 +449,6 @@ namespace Barotrauma
case PropertyConditional.Comparison.And:
foreach (ISerializableEntity target in targets)
{
if (target == null || target.SerializableProperties == null) { continue; }
foreach (PropertyConditional pc in propertyConditionals)
{
if (!string.IsNullOrEmpty(pc.TargetItemComponentName))
@@ -516,6 +515,7 @@ namespace Barotrauma
if (existingEffect != null)
{
existingEffect.Timer = Math.Max(existingEffect.Timer, duration);
existingEffect.User = user;
return;
}
}
@@ -554,6 +554,7 @@ namespace Barotrauma
if (existingEffect != null)
{
existingEffect.Timer = Math.Max(existingEffect.Timer, duration);
existingEffect.User = user;
return;
}
}
@@ -607,7 +608,8 @@ namespace Barotrauma
Parent = this,
Timer = duration,
Entity = entity,
Targets = targets
Targets = targets,
User = user
};
DurationList.Add(element);
@@ -641,6 +643,7 @@ namespace Barotrauma
if (target is Character character)
{
if (character.Removed) { continue; }
character.LastDamageSource = entity;
foreach (Limb limb in character.AnimController.Limbs)
{
@@ -651,6 +654,7 @@ namespace Barotrauma
}
else if (target is Limb limb)
{
if (limb.character.Removed) { continue; }
limb.character.DamageLimb(entity.WorldPosition, limb, new List<Affliction>() { multipliedAffliction }, stun: 0.0f, playSound: false, attackImpulse: 0.0f, attacker: affliction.Source);
}
}
@@ -669,7 +673,7 @@ namespace Barotrauma
targetLimb = limb;
targetCharacter = limb.character;
}
if (targetCharacter != null)
if (targetCharacter != null && !targetCharacter.Removed)
{
float prevVitality = targetCharacter.Vitality;
targetCharacter.CharacterHealth.ReduceAffliction(targetLimb, reduceAffliction.First, reduceAmount);
@@ -827,11 +831,13 @@ namespace Barotrauma
if (target is Character character)
{
character.AddDamage(character.WorldPosition, new List<Affliction>() { multipliedAffliction }, stun: 0.0f, playSound: false);
if (character.Removed) { continue; }
character.AddDamage(character.WorldPosition, new List<Affliction>() { multipliedAffliction }, stun: 0.0f, playSound: false, attacker: element.User);
}
else if (target is Limb limb)
{
limb.character.DamageLimb(limb.WorldPosition, limb, new List<Affliction>() { multipliedAffliction }, stun: 0.0f, playSound: false, attackImpulse: 0.0f);
if (limb.character.Removed) { continue; }
limb.character.DamageLimb(limb.WorldPosition, limb, new List<Affliction>() { multipliedAffliction }, stun: 0.0f, playSound: false, attackImpulse: 0.0f, attacker: element.User);
}
}
@@ -848,12 +854,12 @@ namespace Barotrauma
targetLimb = limb;
targetCharacter = limb.character;
}
if (targetCharacter != null)
if (targetCharacter != null && !targetCharacter.Removed)
{
float prevVitality = targetCharacter.Vitality;
targetCharacter.CharacterHealth.ReduceAffliction(targetLimb, reduceAffliction.First, reduceAffliction.Second * deltaTime);
#if SERVER
GameMain.Server.KarmaManager.OnCharacterHealthChanged(targetCharacter, element.Parent.user, prevVitality - targetCharacter.Vitality);
GameMain.Server.KarmaManager.OnCharacterHealthChanged(targetCharacter, element.User, prevVitality - targetCharacter.Vitality);
#endif
}
}
@@ -861,7 +867,7 @@ namespace Barotrauma
element.Timer -= deltaTime;
if (element.Timer > 0.0f) continue;
if (element.Timer > 0.0f) { continue; }
DurationList.Remove(element);
}
}
@@ -873,20 +879,17 @@ namespace Barotrauma
CoroutineManager.StopCoroutines("statuseffect");
DelayedEffect.DelayList.Clear();
DurationList.Clear();
#if CLIENT
//ActiveLoopingSounds.Clear();
#endif
}
public void AddTag(string tag)
{
if (tags.Contains(tag)) return;
if (tags.Contains(tag)) { return; }
tags.Add(tag);
}
public bool HasTag(string tag)
{
if (tag == null) return true;
if (tag == null) { return true; }
return (tags.Contains(tag) || tags.Contains(tag.ToLowerInvariant()));
}
@@ -311,7 +311,16 @@ namespace Barotrauma
}
}
return string.Format(text, args);
try
{
return string.Format(text, args);
}
catch (FormatException)
{
string errorMsg = "Failed to format text \"" + text + "\", args: " + string.Join(", ", args);
GameAnalyticsManager.AddErrorEventOnce("TextManager.GetFormatted:FormatException", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
return text;
}
}
public static string FormatServerMessage(string textId)
@@ -621,6 +630,8 @@ namespace Barotrauma
static Regex isCJK = new Regex(
@"\p{IsHangulJamo}|" +
@"\p{IsHiragana}|" +
@"\p{IsKatakana}|" +
@"\p{IsCJKRadicalsSupplement}|" +
@"\p{IsCJKSymbolsandPunctuation}|" +
@"\p{IsEnclosedCJKLettersandMonths}|" +
@@ -635,6 +646,7 @@ namespace Barotrauma
/// </summary>
public static bool IsCJK(string text)
{
if (string.IsNullOrEmpty(text)) { return false; }
return isCJK.IsMatch(text);
}
@@ -427,12 +427,8 @@ namespace Barotrauma
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
string temppath = Path.Combine(destDirName, file.Name);
if (overwriteExisting && File.Exists(temppath))
{
File.Delete(temppath);
}
file.CopyTo(temppath, false);
string tempPath = Path.Combine(destDirName, file.Name);
file.CopyTo(tempPath, overwriteExisting);
}
// If copying subdirectories, copy them and their contents to new location.
@@ -440,8 +436,8 @@ namespace Barotrauma
{
foreach (DirectoryInfo subdir in dirs)
{
string temppath = Path.Combine(destDirName, subdir.Name);
CopyFolder(subdir.FullName, temppath, copySubDirs);
string tempPath = Path.Combine(destDirName, subdir.Name);
CopyFolder(subdir.FullName, tempPath, copySubDirs, overwriteExisting);
}
}
}