diff --git a/Barotrauma/BarotraumaClient/ClientCode.projitems b/Barotrauma/BarotraumaClient/ClientCode.projitems
index 489043880..1b79fd2eb 100644
--- a/Barotrauma/BarotraumaClient/ClientCode.projitems
+++ b/Barotrauma/BarotraumaClient/ClientCode.projitems
@@ -213,6 +213,7 @@
+
Never
diff --git a/Barotrauma/BarotraumaClient/Source/StatusEffects/StatusEffect.cs b/Barotrauma/BarotraumaClient/Source/StatusEffects/StatusEffect.cs
new file mode 100644
index 000000000..778e11f82
--- /dev/null
+++ b/Barotrauma/BarotraumaClient/Source/StatusEffects/StatusEffect.cs
@@ -0,0 +1,144 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Barotrauma.Particles;
+using Barotrauma.Sounds;
+using Microsoft.Xna.Framework;
+using System.Xml.Linq;
+using Barotrauma.Items.Components;
+
+namespace Barotrauma
+{
+ partial class StatusEffect
+ {
+ private List particleEmitters;
+
+ private static HashSet ActiveLoopingSounds = new HashSet();
+ private static double LastMuffleCheckTime;
+ private List sounds = new List();
+ private SoundSelectionMode soundSelectionMode;
+ private SoundChannel soundChannel;
+ private Entity soundEmitter;
+ private double loopStartTime;
+ private bool loopSound;
+
+ partial void InitProjSpecific(XElement element, string parentDebugName)
+ {
+ particleEmitters = new List();
+
+ foreach (XElement subElement in element.Elements())
+ {
+ switch (subElement.Name.ToString().ToLowerInvariant())
+ {
+ case "particleemitter":
+ particleEmitters.Add(new ParticleEmitter(subElement));
+ break;
+ case "sound":
+ var sound = Submarine.LoadRoundSound(subElement);
+ if (sound != null)
+ {
+ loopSound = subElement.GetAttributeBool("loop", false);
+ if (subElement.Attribute("selectionmode") != null)
+ {
+ if (Enum.TryParse(subElement.GetAttributeString("selectionmode", "Random"), out SoundSelectionMode selectionMode))
+ {
+ soundSelectionMode = selectionMode;
+ }
+ }
+ sounds.Add(sound);
+ }
+ break;
+ }
+ }
+ }
+
+ partial void ApplyProjSpecific(float deltaTime, Entity entity, List targets, Hull hull)
+ {
+ if (entity != null && sounds.Count > 0)
+ {
+ if (soundChannel == null || !soundChannel.IsPlaying)
+ {
+ if (soundSelectionMode == SoundSelectionMode.All)
+ {
+ foreach (RoundSound sound in sounds)
+ {
+ soundChannel = SoundPlayer.PlaySound(sound.Sound, sound.Volume, sound.Range, entity.WorldPosition, hull);
+ if (soundChannel != null) soundChannel.Looping = loopSound;
+ }
+ }
+ else
+ {
+ int selectedSoundIndex = 0;
+ if (soundSelectionMode == SoundSelectionMode.ItemSpecific && entity is Item item)
+ {
+ selectedSoundIndex = item.ID % sounds.Count;
+ }
+ else if (soundSelectionMode == SoundSelectionMode.CharacterSpecific && entity is Character user)
+ {
+ selectedSoundIndex = user.ID % sounds.Count;
+ }
+ else
+ {
+ selectedSoundIndex = Rand.Int(sounds.Count);
+ }
+ var selectedSound = sounds[selectedSoundIndex];
+ soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, selectedSound.Volume, selectedSound.Range, entity.WorldPosition, hull);
+ if (soundChannel != null) soundChannel.Looping = loopSound;
+ }
+ }
+
+ if (soundChannel != null && soundChannel.Looping)
+ {
+ ActiveLoopingSounds.Add(this);
+ soundEmitter = entity;
+ loopStartTime = Timing.TotalTime;
+ }
+ }
+
+ if (entity != null)
+ {
+ foreach (ParticleEmitter emitter in particleEmitters)
+ {
+ float angle = 0.0f;
+ if (emitter.Prefab.CopyEntityAngle)
+ {
+ if (entity is Item it)
+ {
+ angle = it.body == null ? 0.0f : it.body.Rotation;
+ }
+ }
+
+ emitter.Emit(deltaTime, entity.WorldPosition, hull, angle);
+ }
+ }
+ }
+
+ static partial void UpdateAllProjSpecific(float deltaTime)
+ {
+ bool doMuffleCheck = Timing.TotalTime > LastMuffleCheckTime + 0.2;
+ if (doMuffleCheck) { LastMuffleCheckTime = Timing.TotalTime; }
+ foreach (StatusEffect statusEffect in ActiveLoopingSounds)
+ {
+ if (statusEffect.soundChannel == null) { continue; }
+
+ //stop looping sounds if the statuseffect hasn't been applied in 0.1
+ //= keeping the sound looping requires continuously applying the statuseffect
+ if (Timing.TotalTime > statusEffect.loopStartTime + 0.1)
+ {
+ statusEffect.soundChannel.FadeOutAndDispose();
+ statusEffect.soundChannel = null;
+ }
+ else
+ {
+ statusEffect.soundChannel.Position = new Vector3(statusEffect.soundEmitter.WorldPosition, 0.0f);
+ if (doMuffleCheck)
+ {
+ statusEffect.soundChannel.Muffled = SoundPlayer.ShouldMuffleSound(
+ Character.Controlled, statusEffect.soundEmitter.WorldPosition, statusEffect.soundChannel.Far, Character.Controlled?.CurrentHull);
+ }
+ }
+ }
+ ActiveLoopingSounds.RemoveWhere(s => s.soundChannel == null);
+ }
+ }
+}
diff --git a/Barotrauma/BarotraumaShared/Source/StatusEffects/StatusEffect.cs b/Barotrauma/BarotraumaShared/Source/StatusEffects/StatusEffect.cs
index 072c260ab..42f846423 100644
--- a/Barotrauma/BarotraumaShared/Source/StatusEffects/StatusEffect.cs
+++ b/Barotrauma/BarotraumaShared/Source/StatusEffects/StatusEffect.cs
@@ -1,13 +1,9 @@
-using Microsoft.Xna.Framework;
+using Barotrauma.Items.Components;
+using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
-using Barotrauma.Items.Components;
-#if CLIENT
-using Barotrauma.Particles;
-using Barotrauma.Sounds;
-#endif
namespace Barotrauma
{
@@ -90,20 +86,12 @@ namespace Barotrauma
}
}
+
private TargetType targetTypes;
protected HashSet targetIdentifiers;
private List requiredItems;
-
-#if CLIENT
- private List particleEmitters;
-
- private List sounds = new List();
- private SoundSelectionMode soundSelectionMode;
- private SoundChannel soundChannel;
- private bool loopSound;
-#endif
-
+
public string[] propertyNames;
private object[] propertyEffects;
@@ -193,10 +181,6 @@ namespace Barotrauma
Range = element.GetAttributeFloat("range", 0.0f);
-#if CLIENT
- particleEmitters = new List();
-#endif
-
IEnumerable attributes = element.Attributes();
List propertyAttributes = new List();
propertyConditionals = new List();
@@ -373,28 +357,16 @@ namespace Barotrauma
var newSpawnItem = new ItemSpawnInfo(subElement, parentDebugName);
if (newSpawnItem.ItemPrefab != null) spawnItems.Add(newSpawnItem);
break;
-#if CLIENT
- case "particleemitter":
- particleEmitters.Add(new ParticleEmitter(subElement));
- break;
- case "sound":
- var sound = Submarine.LoadRoundSound(subElement);
- if (sound != null)
- {
- loopSound = subElement.GetAttributeBool("loop", false);
- if (subElement.Attribute("selectionmode") != null)
- {
- if (Enum.TryParse(subElement.GetAttributeString("selectionmode", "Random"), out SoundSelectionMode selectionMode))
- {
- soundSelectionMode = selectionMode;
- }
- }
- sounds.Add(sound);
- }
- break;
-#endif
}
}
+ InitProjSpecific(element, parentDebugName);
+ }
+
+ partial void InitProjSpecific(XElement element, string parentDebugName);
+
+ public bool HasTargetType(TargetType targetType)
+ {
+ return (targetTypes & targetType) != 0;
}
public bool HasTargetType(TargetType targetType)
@@ -601,46 +573,10 @@ namespace Barotrauma
{
hull = ((Item)entity).CurrentHull;
}
-#if CLIENT
- if (entity != null && sounds.Count > 0)
- {
- if (soundChannel == null || !soundChannel.IsPlaying)
- {
- if (soundSelectionMode == SoundSelectionMode.All)
- {
- foreach (RoundSound sound in sounds)
- {
- soundChannel = SoundPlayer.PlaySound(sound.Sound, sound.Volume, sound.Range, entity.WorldPosition, hull);
- if (soundChannel != null) soundChannel.Looping = loopSound;
- }
- }
- else
- {
- int selectedSoundIndex = 0;
- if (soundSelectionMode == SoundSelectionMode.ItemSpecific && entity is Item item)
- {
- selectedSoundIndex = item.ID % sounds.Count;
- }
- else if (soundSelectionMode == SoundSelectionMode.CharacterSpecific && entity is Character user)
- {
- selectedSoundIndex = user.ID % sounds.Count;
- }
- else
- {
- selectedSoundIndex = Rand.Int(sounds.Count);
- }
- var selectedSound = sounds[selectedSoundIndex];
- soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, selectedSound.Volume, selectedSound.Range, entity.WorldPosition, hull);
- if (soundChannel != null) soundChannel.Looping = loopSound;
- }
- }
- }
-#endif
foreach (ISerializableEntity serializableEntity in targets)
{
- Item item = serializableEntity as Item;
- if (item == null) continue;
+ if (!(serializableEntity is Item item)) continue;
Character targetCharacter = targets.FirstOrDefault(t => t is Character character && !character.Removed) as Character;
if (targetCharacter == null)
@@ -740,11 +676,7 @@ namespace Barotrauma
fire.Size = new Vector2(FireSize, fire.Size.Y);
}
- bool isNotClient = true;
-#if CLIENT
- isNotClient = GameMain.Client == null;
-#endif
-
+ bool isNotClient = GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient;
if (isNotClient && entity != null && Entity.Spawner != null) //clients are not allowed to spawn items
{
foreach (ItemSpawnInfo itemSpawnInfo in spawnItems)
@@ -801,26 +733,11 @@ namespace Barotrauma
}
}
-#if CLIENT
- if (entity != null)
- {
- foreach (ParticleEmitter emitter in particleEmitters)
- {
- float angle = 0.0f;
- if (emitter.Prefab.CopyEntityAngle)
- {
- if (entity is Item it)
- {
- angle = it.body == null ? 0.0f : it.body.Rotation;
- }
- }
-
- emitter.Emit(deltaTime, entity.WorldPosition, hull, angle);
- }
- }
-#endif
+ ApplyProjSpecific(deltaTime, entity, targets, hull);
}
+ partial void ApplyProjSpecific(float deltaTime, Entity entity, List targets, Hull currentHull);
+
private void ApplyToProperty(ISerializableEntity target, SerializableProperty property, object value, float deltaTime)
{
if (disableDeltaTime || setValue) deltaTime = 1.0f;
@@ -857,6 +774,8 @@ namespace Barotrauma
public static void UpdateAll(float deltaTime)
{
+ UpdateAllProjSpecific(deltaTime);
+
DelayedEffect.Update(deltaTime);
for (int i = DurationList.Count - 1; i >= 0; i--)
{
@@ -925,11 +844,16 @@ namespace Barotrauma
}
}
+ static partial void UpdateAllProjSpecific(float deltaTime);
+
public static void StopAll()
{
CoroutineManager.StopCoroutines("statuseffect");
DelayedEffect.DelayList.Clear();
DurationList.Clear();
+#if CLIENT
+ //ActiveLoopingSounds.Clear();
+#endif
}
public void AddTag(string tag)