(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
@@ -93,6 +93,7 @@
<Text file="Content/Texts/SimplifiedChineseVanilla.xml" />
<Text file="Content/Texts/TraditionalChineseVanilla.xml" />
<Text file="Content/Texts/CastilianSpanishVanilla.xml" />
<Text file="Content/Texts/JapaneseVanilla.xml" />
<Text file="Content/Texts/LatinamericanSpanishVanilla.xml" />
<Text file="Content/Texts/PolishVanilla.xml" />
<Text file="Content/Texts/TurkishVanilla.xml" />
@@ -117,6 +118,11 @@
<NPCConversations file="Content/NPCConversations/NpcConversations_BrazilianPortuguese.xml"/>
<NPCConversations file="Content/NPCConversations/NpcConversations_SimplifiedChinese.xml"/>
<NPCConversations file="Content/NPCConversations/NpcConversations_TraditionalChinese.xml"/>
<NPCConversations file="Content/NPCConversations/NpcConversations_CastilianSpanish.xml"/>
<NPCConversations file="Content/NPCConversations/NpcConversations_Japanese.xml"/>
<NPCConversations file="Content/NPCConversations/NpcConversations_LatinamericanSpanish.xml"/>
<NPCConversations file="Content/NPCConversations/NpcConversations_Polish.xml"/>
<NPCConversations file="Content/NPCConversations/NpcConversations_Turkish.xml"/>
<Jobs file="Content/Jobs.xml" />
<Sounds file="Content/Sounds/sounds.xml" />
<Tutorials file="Content/Tutorials/Tutorials.xml" />
@@ -7,20 +7,22 @@
karmaincrease="0.1"
karmaincreasethreshold="50"
structurerepairkarmaincrease="0.05"
structuredamagekarmadecrease="0.1"
structuredamagekarmadecrease="0.08"
itemrepairkarmaincrease="0.03"
reactoroverheatkarmadecrease="0.5"
reactormeltdownkarmadecrease="30"
damageenemykarmaincrease="0.1"
damagefriendlykarmadecrease="0.2"
damagefriendlykarmadecrease="0.15"
extinguishfirekarmaincrease="1"
allowedwiredisconnectionsperminute="3"
allowedwiredisconnectionsperminute="5"
wiredisconnectionkarmadecrease="6.0"
steersubkarmaincrease="0.15"
spamfilterkarmadecrease="15"
herpesthreshold="40"
kickbanthreshold="1"
karmanotificationinterval="10" />
kicksbeforeban="3"
karmanotificationinterval="15"
resetkarmabetweenrounds="true" />
<Preset
name="Strict"
karmadecay="0.08"
@@ -35,13 +37,15 @@
damageenemykarmaincrease="0.1"
damagefriendlykarmadecrease="0.3"
extinguishfirekarmaincrease="1"
allowedwiredisconnectionsperminute="1"
allowedwiredisconnectionsperminute="3"
wiredisconnectionkarmadecrease="10.0"
steersubkarmaincrease="0.15"
spamfilterkarmadecrease="25"
herpesthreshold="40"
kickbanthreshold="1"
karmanotificationinterval="10" />
kicksbeforeban="1"
karmanotificationinterval="15"
resetkarmabetweenrounds="true" />
<Preset
name="Custom"
karmadecay="0.08"
@@ -49,18 +53,20 @@
karmaincrease="0.1"
karmaincreasethreshold="50"
structurerepairkarmaincrease="0.05"
structuredamagekarmadecrease="0.1"
structuredamagekarmadecrease="0.08"
itemrepairkarmaincrease="0.03"
reactoroverheatkarmadecrease="0.5"
reactormeltdownkarmadecrease="30"
damageenemykarmaincrease="0.1"
damagefriendlykarmadecrease="0.2"
damagefriendlykarmadecrease="0.15"
extinguishfirekarmaincrease="1"
allowedwiredisconnectionsperminute="3"
allowedwiredisconnectionsperminute="5"
wiredisconnectionkarmadecrease="6.0"
steersubkarmaincrease="0.15"
spamfilterkarmadecrease="15"
herpesthreshold="40"
kickbanthreshold="1"
karmanotificationinterval="10" />
kicksbeforeban="3"
karmanotificationinterval="15"
resetkarmabetweenrounds="true" />
</KarmaManager>
@@ -592,6 +592,9 @@
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_BrazilianPortuguese.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_CastilianSpanish.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_English.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -602,6 +605,15 @@
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_German.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_Japanese.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_LatinamericanSpanish.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_Polish.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_Russian.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -611,6 +623,9 @@
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_TraditionalChinese.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_Turkish.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Splash_Daedalic.mp4">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -635,6 +650,9 @@
<Content Include="$(MSBuildThisFileDirectory)Content\Texts\GermanVanilla.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Texts\JapaneseVanilla.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Texts\LatinamericanSpanishVanilla.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -2399,6 +2417,12 @@
<None Include="$(MSBuildThisFileDirectory)Content\Sounds\Impact\SoftImpact3.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Sounds\RepairLoop.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Sounds\RewiringLoop.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Tutorials\Dugong_Tutorial.sub">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
@@ -2420,6 +2444,9 @@
<None Include="$(MSBuildThisFileDirectory)Content\TraitorMissions.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Submarines\Nautilus.sub">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)Content\Characters\Carrier\CARRIER_alarmLoop.ogg">
@@ -3593,4 +3620,4 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
</Project>
@@ -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);
}
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+129
View File
@@ -1,3 +1,132 @@
---------------------------------------------------------------------------------------------------------
v0.9.3.2
---------------------------------------------------------------------------------------------------------
- Fixed a networking error that prevented clients from selecting the correct submarine in multiplayer if
the settings menu had been toggled open, which caused the client to start the round with an incorrect
submarine and get kicked out from the server due to entity ID mismatch errors.
- Added Japanese translation.
- Added Polish, Spanish and Turkish NPC conversations.
- Improvements to Russian and Spanish translations.
---------------------------------------------------------------------------------------------------------
v0.9.3.1
---------------------------------------------------------------------------------------------------------
- Fixed clients waiting an excessive amount of time before resending network messages the server has not
acknowledged receiving. Caused clients to occasionally enter a state where they can't interact with devices
or pick up items.
- Fixed fonts getting messed up when playing in Simplified Chinese.
---------------------------------------------------------------------------------------------------------
v0.9.3.0
---------------------------------------------------------------------------------------------------------
Traitor improvements:
- Players who haven't been a traitor yet are more likely to get selected as a traitor.
- If both teams have a traitor during a combat mission, traitor win will result in the opposite team's victory.
- Fixed the order of the traitor objective chat messages.
- Fixed flooding the respawn shuttle counting as flooding a part of the submarine when doing the "flood
the submarine" traitor task.
Multiplayer fixes:
- Fixed server not sending a condition update for an item that gets removed when its condition drops to zero.
Caused potassium and magnesium to explode continuously client-side when immersed in water.
- Fixed server list only displaying servers that are located close to the client.
- Fixed server list displaying the selected game mode incorrectly.
- Fixed Chinese server names and descriptions showing up as "?????" in the server list when not playing in Chinese.
- Fixed occasional "error while reading a message from the server" console errors when joining a server.
- Fixed clients occasionally timing out and disconnecting during the loading screens.
- Fixed character name box resetting in the server lobby when another client joins or disconnects.
- Fixed "collection was modified" error when a client who's been given control of a bot tries to use
the report buttons.
- Fixed server hanging when a client joins if the server has a very large number of submarines installed.
- Fixed a bunch of client-side console commands crashing the game if the client disconnects while a question
prompt is active and then enters something in the console.
- Fixed full SteamP2P servers not showing up on the server list regardless of the filters.
- Fixed "remove ban" and "range ban" buttons in the server settings menu doing nothing.
- Fixed switches occasionally getting desynced between clients.
- Added a tickbox for selecting/deselecting all permissions to the client management panel.
- Fixed clients with campaign management permissions not seeing the permissions of newly joined clients.
- Fixed statuseffects with a duration not having an effect on karma.
- Causing an "oxygen low" affliction decreases karma (for example when injecting large amounts of fentanyl).
- Fixed scroll values resetting in the multiplayer campaign store menu when purchasing/selling items.
Miscellaneous improvements:
- Attempting to drop an item to an empty inventory slot that's not of the right type (e.g. trying to put
an extinguisher in the normal inventory slots), automatically moves the item to the correct slot if it's free.
- Made irrelevant items (light components, lamps, small automated pumps, etc) non-interactable in the tutorials.
- The first patient cannot be healed in the doctor tutorial until the "take the patient to the medbay"
objective has been completed.
- The docking interface does not become active in the captain tutorial when leaving the first outpost.
- Added sounds for rewiring and repairing.
Miscellaneous fixes:
- Fixed skills not having any effect on repair durations.
- Fixed inability to enable content packages created for a version prior to 0.9.2.0 (ones that have the
content package in the Data/ContentPackages folder instead of in the mod folder).
- Use a welding tool icon to indicate damaged walls in the mechanic tutorial, because the generic repair
icon caused some players to think the wall needs to be repaired with a wrench.
- Minor changes to the instruction texts in the mechanic tutorial.
- Reduced repair durations in the engineer/mechanic tutorials.
- Fixed draggable subinventories staying visible when stunned.
- Fixed light sprites not being scaled in the sub editor when resizing lamps.
- Fixed contained items not changing their position when flipping the container (e.g. oxygen generator
with some tanks inside).
- Fixed projectiles emitting sparks when they hit a character (not just when they hit a structure).
- Fixed sonar's zoom slider not moving when autodocking zooms in.
- Fixed small creatures being unable to reach waypoints.
- Fixed bots getting stuck while trying to repair items (in practice hatches) while holding ladders.
- Hid SMG rounds and coilgun bolts from the sub editor because they're not usable by themselves, but are
spawned automatically when the SMG/coilgun is fired.
- Hid the junction box tutorial variant from the sub editor.
- Stun guns and darts can be fabricated and purchased.
- More reliable melee weapon hit detection (for example in the security tutorial it was previously very
difficult to hit the crawler after it falls to the ground).
- Enemies steer back towards the level if they end up outside the boundaries.
- Added confirmation popups when exiting the sub editor or character editor to prevent losing unsaved work.
- Fixed reactor warning lights being clickable and becoming invisible when pressed.
- Fixed CPR button becoming invisible when pressed.
- Fixed water occasionally flowing only through one gap in a hull, for example water only draining
through a hole at a one side of a room even if there is another hole at the other side of the room.
- Fixed scrollbars not resizing when filtering lists (e.g. the submarine list in the "new game" menu).
- Fixed being able to fire flamers (and other repair tools) through walls and doors.
- Fixed flamers working underwater when the water is shallow enough for the character to stand.
- Fixed battery recharge rate slider not moving when the recharge rate is set by an incoming signal
or a remote player.
- Fixed some connection panels being rewireable in vanilla subs when a wire is equipped.
- Fixed some pre-placed body armors and grenades in vanilla subs having an incorrect scale.
- Fixed crashing when a character gains a skill level on a skill that's not initially configured
for the character class.
- Fixed "Add File" dialog of the Workshop publish screen always using the mod's root folder as the file
path even if the file is in a subfolder.
- Fixed contentpackage version number not being updated when updating an older workshop item.
- Fixed subinventories closing when items are dropped into or removed from them, which made reloading
weapons or putting several items into a container cumbersome.
---------------------------------------------------------------------------------------------------------
v0.9.2.2
---------------------------------------------------------------------------------------------------------
Karma improvements:
- Attacking someone who has just recently attacked you doesn't reduce karma.
- The karma penalty from attacking someone scales according to their karma (i.e. smaller penalty for
attacking a griefer whose karma is low).
- Damaging characters by performing CPR doesn't decrease karma.
- Fixed karma decreasing when moving a wire from a connection to another.
- Reviving characters with CPR increases karma.
- Made the default karma settings a little less strict.
- Fixed clients always getting kicked (never banned) if the "kicks before ban" karma setting is set above 0.
- Players aren't notified about their karma decreasing when it decreases "naturally" towards the neutral
value of 50.
Bugfixes:
- Fixed mechanic tutorial crashing after the welding task when playing in Russian.
- Less restrictive client name symbol constraints. Fixes clients failing to join servers if their name
contains Chinese symbols for example.
- Fixed inability to enable/update content packages created for a version prior to 0.9.2.0 (ones that have
the content package in the Data/ContentPackages folder instead of in the mod folder).
---------------------------------------------------------------------------------------------------------
v0.9.2.1
---------------------------------------------------------------------------------------------------------
@@ -48,5 +48,5 @@
autorestart="false"
LevelDifficulty="20"
AllowedRandomMissionTypes="Random,Salvage,Monster,Cargo,Combat"
AllowedClientNameChars="32-33,38-46,48-57,65-90,91-91,93-93,95-122,192-255,384-591,1024-1279"
AllowedClientNameChars="32-33,38-46,48-57,65-90,91-91,93-93,95-122,192-255,384-591,1024-1279,19968-40959,13312-19903,131072-173791,173824-178207,178208-183983,63744-64255,194560-195103"
ServerMessage="" />