diff --git a/Content.Shared/_ES/Camera/ESScreenshakeSystem.cs b/Content.Shared/_ES/Camera/ESScreenshakeSystem.cs index 7901d753ab..584d2fb785 100644 --- a/Content.Shared/_ES/Camera/ESScreenshakeSystem.cs +++ b/Content.Shared/_ES/Camera/ESScreenshakeSystem.cs @@ -1,6 +1,7 @@ using System.Linq; using System.Numerics; using Content.Shared.Camera; +using Robust.Shared.Map; using Robust.Shared.Noise; using Robust.Shared.Player; using Robust.Shared.Random; @@ -14,6 +15,7 @@ namespace Content.Shared._ES.Camera; /// public sealed class ESScreenshakeSystem : EntitySystem { + [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IGameTiming _timing = default!; @@ -197,5 +199,100 @@ public void Screenshake(Filter filter, ESScreenshakeParameters? translation, ESS } } + + // lerped screenshakes + /// + /// Applies a lerped screenshake effect to everything within PVS of the target. The further away you are, the less screenshake you recieve. + /// + public void LerpedShake(MapCoordinates pos, float trauma, float decay, float frequency, float maxRange) + { + var shakeFilter = Filter.Empty().AddPlayersByPvs(pos); + + foreach (var player in shakeFilter.Recipients) + { + if (player.AttachedEntity == null) + continue; // huh??? + var playerPos = _transform.ToMapCoordinates(Transform(player.AttachedEntity.Value).Coordinates); + var distance = (playerPos.Position - pos.Position).LengthSquared() / maxRange; + distance = Math.Clamp(distance, 0f, maxRange); // clamp it to prevent nonsense + + var lerpedTrauma = MathHelper.Lerp(trauma, trauma/2f, distance); + var lerpedDecay = MathHelper.Lerp(decay, decay*2f, distance); + var lerpedFrequency = MathHelper.Lerp(frequency, frequency/2, distance); + var shake = new ESScreenshakeParameters() { Trauma = lerpedTrauma, DecayRate = lerpedDecay, Frequency = lerpedFrequency}; + Screenshake(player.AttachedEntity.Value, shake, null); + } + } + + /// + /// Applies a lerped screenshake effect to everything within PVS of the target. The further away you are, the less screenshake you recieve. + /// + public void LerpedShake(EntityUid ent, float trauma, float decay, float frequency, float maxRange) + { + var pos = _transform.GetMapCoordinates(ent); + var shakeFilter = Filter.Empty().AddPlayersByPvs(pos); + + foreach (var player in shakeFilter.Recipients) + { + if (player.AttachedEntity == null) + continue; // huh??? + var playerPos = _transform.ToMapCoordinates(Transform(player.AttachedEntity.Value).Coordinates); + var distance = (playerPos.Position - pos.Position).LengthSquared() / maxRange; + distance = Math.Clamp(distance, 0f, maxRange); // clamp it to prevent nonsense + + var lerpedTrauma = MathHelper.Lerp(trauma, trauma/2f, distance); + var lerpedDecay = MathHelper.Lerp(decay, decay*2f, distance); + var lerpedFrequency = MathHelper.Lerp(frequency, frequency/2, distance); + var shake = new ESScreenshakeParameters() { Trauma = lerpedTrauma, DecayRate = lerpedDecay, Frequency = lerpedFrequency}; + Screenshake(player.AttachedEntity.Value, shake, null); + } + } + + /// + /// Applies a lerped screenshake effect to everything within range of the target. The further away you are, the less screenshake you recieve. + /// + public void LerpedShake(MapCoordinates pos, int range, float trauma, float decay, float frequency, float maxRange) + { + var shakeFilter = Filter.Empty().AddInRange(pos, range); + + foreach (var player in shakeFilter.Recipients) + { + if (player.AttachedEntity == null) + continue; // huh??? + var playerPos = _transform.ToMapCoordinates(Transform(player.AttachedEntity.Value).Coordinates); + var distance = (playerPos.Position - pos.Position).LengthSquared() / maxRange; + distance = Math.Clamp(distance, 0f, maxRange); // clamp it to prevent nonsense + + var lerpedTrauma = MathHelper.Lerp(trauma, trauma/2f, distance); + var lerpedDecay = MathHelper.Lerp(decay, decay*2f, distance); + var lerpedFrequency = MathHelper.Lerp(frequency, frequency/2, distance); + var shake = new ESScreenshakeParameters() { Trauma = lerpedTrauma, DecayRate = lerpedDecay, Frequency = lerpedFrequency}; + Screenshake(player.AttachedEntity.Value, shake, null); + } + } + + /// + /// Applies a lerped screenshake effect to everything within range of the target. The further away you are, the less screenshake you recieve. + /// + public void LerpedShake(EntityUid ent, int range, float trauma, float decay, float frequency, float maxRange) + { + var pos = _transform.GetMapCoordinates(ent); + var shakeFilter = Filter.Empty().AddInRange(pos, range); + + foreach (var player in shakeFilter.Recipients) + { + if (player.AttachedEntity == null) + continue; // huh??? + var playerPos = _transform.ToMapCoordinates(Transform(player.AttachedEntity.Value).Coordinates); + var distance = (playerPos.Position - pos.Position).LengthSquared() / maxRange; + distance = Math.Clamp(distance, 0f, maxRange); // clamp it to prevent nonsense + + var lerpedTrauma = MathHelper.Lerp(trauma, trauma/2f, distance); + var lerpedDecay = MathHelper.Lerp(decay, decay*2f, distance); + var lerpedFrequency = MathHelper.Lerp(frequency, frequency/2, distance); + var shake = new ESScreenshakeParameters() { Trauma = lerpedTrauma, DecayRate = lerpedDecay, Frequency = lerpedFrequency}; + Screenshake(player.AttachedEntity.Value, shake, null); + } + } #endregion }