diff --git a/Content.Client/Effects/ColorFlashEffectSystem.cs b/Content.Client/Effects/ColorFlashEffectSystem.cs
new file mode 100644
index 0000000000..b14c11a39e
--- /dev/null
+++ b/Content.Client/Effects/ColorFlashEffectSystem.cs
@@ -0,0 +1,107 @@
+using Content.Shared.Effects;
+using Robust.Client.Animations;
+using Robust.Client.GameObjects;
+using Robust.Shared.Animations;
+
+namespace Content.Client.Effects;
+
+public sealed class ColorFlashEffectSystem : EntitySystem
+{
+ [Dependency] private readonly AnimationPlayerSystem _animation = default!;
+
+ ///
+ /// It's a little on the long side but given we use multiple colours denoting what happened it makes it easier to register.
+ ///
+ private const float AnimationLength = 0.30f;
+ private const string AnimationKey = "color-flash-effect";
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeAllEvent(OnColorFlashEffect);
+ SubscribeLocalEvent(OnEffectAnimationCompleted);
+ }
+
+ private void OnEffectAnimationCompleted(EntityUid uid, ColorFlashEffectComponent component, AnimationCompletedEvent args)
+ {
+ if (args.Key != AnimationKey)
+ return;
+
+ if (TryComp(uid, out var sprite))
+ {
+ sprite.Color = component.Color;
+ }
+
+ RemCompDeferred(uid);
+ }
+
+ private Animation? GetDamageAnimation(EntityUid uid, Color color, SpriteComponent? sprite = null)
+ {
+ if (!Resolve(uid, ref sprite, false))
+ return null;
+
+ // 90% of them are going to be this so why allocate a new class.
+ return new Animation
+ {
+ Length = TimeSpan.FromSeconds(AnimationLength),
+ AnimationTracks =
+ {
+ new AnimationTrackComponentProperty
+ {
+ ComponentType = typeof(SpriteComponent),
+ Property = nameof(SpriteComponent.Color),
+ InterpolationMode = AnimationInterpolationMode.Linear,
+ KeyFrames =
+ {
+ new AnimationTrackProperty.KeyFrame(color, 0f),
+ new AnimationTrackProperty.KeyFrame(sprite.Color, AnimationLength)
+ }
+ }
+ }
+ };
+ }
+
+ private void OnColorFlashEffect(ColorFlashEffectEvent ev)
+ {
+ var color = ev.Color;
+
+ foreach (var ent in ev.Entities)
+ {
+ if (Deleted(ent))
+ {
+ continue;
+ }
+
+ var player = EnsureComp(ent);
+ player.NetSyncEnabled = false;
+
+ // Need to stop the existing animation first to ensure the sprite color is fixed.
+ // Otherwise we might lerp to a red colour instead.
+ if (_animation.HasRunningAnimation(ent, player, AnimationKey))
+ {
+ _animation.Stop(ent, player, AnimationKey);
+ }
+
+ if (!TryComp(ent, out var sprite))
+ {
+ continue;
+ }
+
+ if (TryComp(ent, out var effect))
+ {
+ sprite.Color = effect.Color;
+ }
+
+ var animation = GetDamageAnimation(ent, color, sprite);
+
+ if (animation == null)
+ continue;
+
+ var comp = EnsureComp(ent);
+ comp.NetSyncEnabled = false;
+ comp.Color = sprite.Color;
+ _animation.Play(player, animation, AnimationKey);
+ }
+ }
+}
diff --git a/Content.Client/Replay/ContentReplayPlaybackManager.cs b/Content.Client/Replay/ContentReplayPlaybackManager.cs
index 55491429ea..a96752383a 100644
--- a/Content.Client/Replay/ContentReplayPlaybackManager.cs
+++ b/Content.Client/Replay/ContentReplayPlaybackManager.cs
@@ -5,13 +5,13 @@ using Content.Client.Replay.Spectator;
using Content.Client.Replay.UI.Loading;
using Content.Client.UserInterface.Systems.Chat;
using Content.Shared.Chat;
+using Content.Shared.Effects;
using Content.Shared.GameTicking;
using Content.Shared.GameWindow;
using Content.Shared.Hands;
using Content.Shared.Instruments;
using Content.Shared.Popups;
using Content.Shared.Projectiles;
-using Content.Shared.Weapons.Melee;
using Content.Shared.Weapons.Melee.Events;
using Content.Shared.Weapons.Ranged.Events;
using Content.Shared.Weapons.Ranged.Systems;
@@ -24,9 +24,7 @@ using Robust.Client.Replays.Playback;
using Robust.Client.State;
using Robust.Client.Timing;
using Robust.Client.UserInterface;
-using Robust.Shared.ContentPack;
using Robust.Shared.Serialization.Markdown.Mapping;
-using Robust.Shared.Utility;
namespace Content.Client.Replay;
@@ -66,7 +64,7 @@ public sealed class ContentReplayPlaybackManager
private void LoadOverride(IReplayFileReader fileReader)
{
var screen = _stateMan.RequestStateChange>();
- screen.Job = new ContentLoadReplayJob(1/60f, fileReader, _loadMan, screen);
+ screen.Job = new ContentLoadReplayJob(1 / 60f, fileReader, _loadMan, screen);
screen.OnJobFinished += (_, e) => OnFinishedLoading(e);
}
@@ -141,7 +139,7 @@ public sealed class ContentReplayPlaybackManager
case SharedGunSystem.HitscanEvent:
case ImpactEffectEvent:
case MuzzleFlashEvent:
- case DamageEffectEvent:
+ case ColorFlashEffectEvent:
case InstrumentStartMidiEvent:
case InstrumentMidiEventEvent:
case InstrumentStopMidiEvent:
@@ -159,7 +157,7 @@ public sealed class ContentReplayPlaybackManager
private void OnReplayPlaybackStopped()
{
- _conGrp.Implementation = (IClientConGroupImplementation)_adminMan;
+ _conGrp.Implementation = (IClientConGroupImplementation) _adminMan;
ReturnToDefaultState();
}
}
diff --git a/Content.Client/Weapons/Melee/MeleeWeaponSystem.Effects.cs b/Content.Client/Weapons/Melee/MeleeWeaponSystem.Effects.cs
index f841c9bff5..7dce555817 100644
--- a/Content.Client/Weapons/Melee/MeleeWeaponSystem.Effects.cs
+++ b/Content.Client/Weapons/Melee/MeleeWeaponSystem.Effects.cs
@@ -1,7 +1,5 @@
using System.Numerics;
using Content.Client.Weapons.Melee.Components;
-using Content.Shared.Weapons;
-using Content.Shared.Weapons.Melee;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
using Robust.Shared.Animations;
@@ -11,106 +9,10 @@ namespace Content.Client.Weapons.Melee;
public sealed partial class MeleeWeaponSystem
{
- ///
- /// It's a little on the long side but given we use multiple colours denoting what happened it makes it easier to register.
- ///
- private const float DamageAnimationLength = 0.30f;
-
- private const string DamageAnimationKey = "damage-effect";
private const string FadeAnimationKey = "melee-fade";
private const string SlashAnimationKey = "melee-slash";
private const string ThrustAnimationKey = "melee-thrust";
- private void InitializeEffect()
- {
- SubscribeLocalEvent(OnEffectAnimation);
- }
-
- private void OnEffectAnimation(EntityUid uid, DamageEffectComponent component, AnimationCompletedEvent args)
- {
- if (args.Key != DamageAnimationKey)
- return;
-
- if (TryComp(uid, out var sprite))
- {
- sprite.Color = component.Color;
- }
-
- RemCompDeferred(uid);
- }
-
- ///
- /// Gets the red effect animation whenever the server confirms something is hit
- ///
- private Animation? GetDamageAnimation(EntityUid uid, Color color, SpriteComponent? sprite = null)
- {
- if (!Resolve(uid, ref sprite, false))
- return null;
-
- // 90% of them are going to be this so why allocate a new class.
- return new Animation
- {
- Length = TimeSpan.FromSeconds(DamageAnimationLength),
- AnimationTracks =
- {
- new AnimationTrackComponentProperty
- {
- ComponentType = typeof(SpriteComponent),
- Property = nameof(SpriteComponent.Color),
- InterpolationMode = AnimationInterpolationMode.Linear,
- KeyFrames =
- {
- new AnimationTrackProperty.KeyFrame(color, 0f),
- new AnimationTrackProperty.KeyFrame(sprite.Color, DamageAnimationLength)
- }
- }
- }
- };
- }
-
- private void OnDamageEffect(DamageEffectEvent ev)
- {
- var color = ev.Color;
-
- foreach (var ent in ev.Entities)
- {
- if (Deleted(ent))
- {
- continue;
- }
-
- var player = EnsureComp(ent);
- player.NetSyncEnabled = false;
-
- // Need to stop the existing animation first to ensure the sprite color is fixed.
- // Otherwise we might lerp to a red colour instead.
- if (_animation.HasRunningAnimation(ent, player, DamageAnimationKey))
- {
- _animation.Stop(ent, player, DamageAnimationKey);
- }
-
- if (!TryComp(ent, out var sprite))
- {
- continue;
- }
-
- if (TryComp(ent, out var effect))
- {
- sprite.Color = effect.Color;
- }
-
- var animation = GetDamageAnimation(ent, color, sprite);
-
- if (animation == null)
- continue;
-
- var comp = EnsureComp(ent);
- comp.NetSyncEnabled = false;
- comp.Color = sprite.Color;
- _animation.Play(player, animation, DamageAnimationKey);
- }
- }
-
///
/// Does all of the melee effects for a player that are predicted, i.e. character lunge and weapon animation.
///
diff --git a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs
index 573c6c7265..d77537c051 100644
--- a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs
+++ b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs
@@ -1,6 +1,7 @@
using System.Linq;
using Content.Client.Gameplay;
using Content.Shared.CombatMode;
+using Content.Shared.Effects;
using Content.Shared.Hands.Components;
using Content.Shared.Mobs.Components;
using Content.Shared.StatusEffect;
@@ -37,9 +38,7 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem
public override void Initialize()
{
base.Initialize();
- InitializeEffect();
_overlayManager.AddOverlay(new MeleeWindupOverlay(EntityManager, _timing, _player, _protoManager));
- SubscribeAllEvent(OnDamageEffect);
SubscribeNetworkEvent(OnMeleeLunge);
UpdatesOutsidePrediction = true;
}
@@ -227,7 +226,7 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem
{
// Server never sends the event to us for predictiveeevent.
if (_timing.IsFirstTimePredicted)
- RaiseLocalEvent(new DamageEffectEvent(Color.Red, targets));
+ RaiseLocalEvent(new ColorFlashEffectEvent(Color.Red, targets));
}
protected override bool DoDisarm(EntityUid user, DisarmAttackEvent ev, EntityUid meleeUid, MeleeWeaponComponent component, ICommonSession? session)
diff --git a/Content.Server/Projectiles/ProjectileSystem.cs b/Content.Server/Projectiles/ProjectileSystem.cs
index 5529a5f4f6..e8a7bc0e45 100644
--- a/Content.Server/Projectiles/ProjectileSystem.cs
+++ b/Content.Server/Projectiles/ProjectileSystem.cs
@@ -5,12 +5,10 @@ using Content.Shared.Damage;
using Content.Shared.Database;
using Content.Shared.FixedPoint;
using Content.Shared.Projectiles;
-using Content.Shared.Weapons.Melee;
-using JetBrains.Annotations;
using Robust.Server.GameObjects;
-using Robust.Shared.GameStates;
using Robust.Shared.Player;
using Robust.Shared.Physics.Events;
+using Content.Shared.Effects;
namespace Content.Server.Projectiles;
@@ -52,7 +50,7 @@ public sealed class ProjectileSystem : SharedProjectileSystem
{
if (modifiedDamage.Total > FixedPoint2.Zero && !deleted)
{
- RaiseNetworkEvent(new DamageEffectEvent(Color.Red, new List {otherEntity}), Filter.Pvs(otherEntity, entityManager: EntityManager));
+ RaiseNetworkEvent(new ColorFlashEffectEvent(Color.Red, new List { otherEntity }), Filter.Pvs(otherEntity, entityManager: EntityManager));
}
_adminLogger.Add(LogType.BulletHit,
diff --git a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs
index bb0442b671..2e3104eea2 100644
--- a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs
+++ b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs
@@ -9,11 +9,9 @@ using Content.Server.CombatMode.Disarm;
using Content.Server.Contests;
using Content.Server.Examine;
using Content.Server.Movement.Systems;
-using Content.Server.Popups;
using Content.Shared.Administration.Components;
using Content.Shared.Actions.Events;
using Content.Shared.CombatMode;
-using Content.Shared.Damage;
using Content.Shared.Database;
using Content.Shared.FixedPoint;
using Content.Shared.Hands.Components;
@@ -33,6 +31,7 @@ using Robust.Shared.Player;
using Robust.Shared.Players;
using Robust.Shared.Random;
using Robust.Shared.Utility;
+using Content.Shared.Effects;
namespace Content.Server.Weapons.Melee;
@@ -193,7 +192,7 @@ public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem
var eventArgs = new DisarmedEvent { Target = target, Source = user, PushProbability = 1 - chance };
RaiseLocalEvent(target, eventArgs);
- RaiseNetworkEvent(new DamageEffectEvent(Color.Aqua, new List() { target }));
+ RaiseNetworkEvent(new ColorFlashEffectEvent(Color.Aqua, new List() { target }));
return true;
}
@@ -219,7 +218,7 @@ public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem
protected override void DoDamageEffect(List targets, EntityUid? user, TransformComponent targetXform)
{
var filter = Filter.Pvs(targetXform.Coordinates, entityMan: EntityManager).RemoveWhereAttachedEntity(o => o == user);
- RaiseNetworkEvent(new DamageEffectEvent(Color.Red, targets), filter);
+ RaiseNetworkEvent(new ColorFlashEffectEvent(Color.Red, targets), filter);
}
private float CalculateDisarmChance(EntityUid disarmer, EntityUid disarmed, EntityUid? inTargetHand, CombatModeComponent disarmerComp)
diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs
index 90f67c2890..be24ef4eee 100644
--- a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs
+++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs
@@ -10,6 +10,7 @@ using Content.Server.Weapons.Ranged.Components;
using Content.Shared.Damage;
using Content.Shared.Damage.Systems;
using Content.Shared.Database;
+using Content.Shared.Effects;
using Content.Shared.FixedPoint;
using Content.Shared.Interaction.Components;
using Content.Shared.Projectiles;
@@ -225,7 +226,7 @@ public sealed partial class GunSystem : SharedGunSystem
{
var hitEntity = lastHit.Value;
if (hitscan.StaminaDamage > 0f)
- _stamina.TakeStaminaDamage(hitEntity, hitscan.StaminaDamage, source:user);
+ _stamina.TakeStaminaDamage(hitEntity, hitscan.StaminaDamage, source: user);
var dmg = hitscan.Damage;
@@ -239,7 +240,7 @@ public sealed partial class GunSystem : SharedGunSystem
if (!Deleted(hitEntity))
{
if (dmg.Total > FixedPoint2.Zero)
- RaiseNetworkEvent(new DamageEffectEvent(Color.Red, new List {hitEntity}), Filter.Pvs(hitEntity, entityManager: EntityManager));
+ RaiseNetworkEvent(new ColorFlashEffectEvent(Color.Red, new List { hitEntity }), Filter.Pvs(hitEntity, entityManager: EntityManager));
// TODO get fallback position for playing hit sound.
PlayImpactSound(hitEntity, dmg, hitscan.Sound, hitscan.ForceSound);
@@ -343,7 +344,7 @@ public sealed partial class GunSystem : SharedGunSystem
return angle;
}
- protected override void Popup(string message, EntityUid? uid, EntityUid? user) {}
+ protected override void Popup(string message, EntityUid? uid, EntityUid? user) { }
protected override void CreateEffect(EntityUid uid, MuzzleFlashEvent message, EntityUid? user = null)
{
diff --git a/Content.Shared/Cuffs/SharedCuffableSystem.cs b/Content.Shared/Cuffs/SharedCuffableSystem.cs
index 470256c9a6..8de24c3c1f 100644
--- a/Content.Shared/Cuffs/SharedCuffableSystem.cs
+++ b/Content.Shared/Cuffs/SharedCuffableSystem.cs
@@ -8,6 +8,7 @@ using Content.Shared.Cuffs.Components;
using Content.Shared.Damage;
using Content.Shared.Database;
using Content.Shared.DoAfter;
+using Content.Shared.Effects;
using Content.Shared.Hands;
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
@@ -26,7 +27,6 @@ using Content.Shared.Pulling.Events;
using Content.Shared.Rejuvenate;
using Content.Shared.Stunnable;
using Content.Shared.Verbs;
-using Content.Shared.Weapons.Melee;
using Content.Shared.Weapons.Melee.Events;
using Robust.Shared.Containers;
using Robust.Shared.Network;
@@ -592,7 +592,7 @@ namespace Content.Shared.Cuffs
if (target == user)
{
- RaiseNetworkEvent(new DamageEffectEvent(Color.Red, new List() { user }));
+ RaiseNetworkEvent(new ColorFlashEffectEvent(Color.Red, new List() { user }));
_popup.PopupEntity(Loc.GetString("cuffable-component-start-uncuffing-self"), user, user);
}
else
diff --git a/Content.Shared/Effects/ColorFlashEffectComponent.cs b/Content.Shared/Effects/ColorFlashEffectComponent.cs
new file mode 100644
index 0000000000..3a9895e9c0
--- /dev/null
+++ b/Content.Shared/Effects/ColorFlashEffectComponent.cs
@@ -0,0 +1,11 @@
+namespace Content.Shared.Effects;
+
+///
+/// Stores the original sprite color for flashing entity to be able to restore it later.
+///
+[RegisterComponent]
+public sealed class ColorFlashEffectComponent : Component
+{
+ [ViewVariables]
+ public Color Color = Color.White;
+}
diff --git a/Content.Shared/Effects/ColorFlashEffectEvent.cs b/Content.Shared/Effects/ColorFlashEffectEvent.cs
new file mode 100644
index 0000000000..7dca9c5f41
--- /dev/null
+++ b/Content.Shared/Effects/ColorFlashEffectEvent.cs
@@ -0,0 +1,23 @@
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Effects;
+
+///
+/// Raised on the server and sent to a client to play the color flash animation.
+///
+[Serializable, NetSerializable]
+public sealed class ColorFlashEffectEvent : EntityEventArgs
+{
+ ///
+ /// Color to play for the flash.
+ ///
+ public Color Color;
+
+ public List Entities;
+
+ public ColorFlashEffectEvent(Color color, List entities)
+ {
+ Color = color;
+ Entities = entities;
+ }
+}
\ No newline at end of file
diff --git a/Content.Shared/Weapons/DamageEffectComponent.cs b/Content.Shared/Weapons/DamageEffectComponent.cs
deleted file mode 100644
index 8574e30065..0000000000
--- a/Content.Shared/Weapons/DamageEffectComponent.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace Content.Shared.Weapons;
-
-///
-/// Stores the original sprite color for a damaged entity to be able to restore it later.
-///
-[RegisterComponent]
-public sealed class DamageEffectComponent : Component
-{
- [ViewVariables]
- public Color Color = Color.White;
-}
diff --git a/Content.Shared/Weapons/Melee/DamageEffectEvent.cs b/Content.Shared/Weapons/Melee/DamageEffectEvent.cs
deleted file mode 100644
index ed5eb15a02..0000000000
--- a/Content.Shared/Weapons/Melee/DamageEffectEvent.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using Robust.Shared.Serialization;
-
-namespace Content.Shared.Weapons.Melee;
-
-///
-/// Raised on the server and sent to a client to play the damage animation.
-///
-[Serializable, NetSerializable]
-public sealed class DamageEffectEvent : EntityEventArgs
-{
- ///
- /// Color to play for the damage flash.
- ///
- public Color Color;
-
- public List Entities;
-
- public DamageEffectEvent(Color color, List entities)
- {
- Color = color;
- Entities = entities;
- }
-}