"Reduce motion of visual effects" now works for blood loss effect (#41878)

* "Reduce motion of visual effects" now works for blood loss effect

* Improve strenght

* Make motion less strong

* Stop motion effect

* cleanup and rebalancing

* fix warning

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
This commit is contained in:
Marchy 2026-03-28 23:06:30 +01:00 committed by Coryler
parent 81fa41913b
commit 02e9751013
3 changed files with 51 additions and 21 deletions

View File

@ -1,8 +1,8 @@
using Content.Shared.CCVar;
using Content.Shared.Drunk;
using Content.Shared.StatusEffect;
using Content.Shared.StatusEffectNew;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Configuration;
using Robust.Shared.Enums;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
@ -11,19 +11,23 @@ namespace Content.Client.Drunk;
public sealed class DrunkOverlay : Overlay
{
private static readonly ProtoId<ShaderPrototype> Shader = "Drunk";
private static readonly ProtoId<ShaderPrototype> DrunkShader = "Drunk";
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IConfigurationManager _configManager = default!;
private readonly Shared.StatusEffectNew.StatusEffectsSystem _statusEffectsSystem;
public override OverlaySpace Space => OverlaySpace.WorldSpace;
public override bool RequestScreenTexture => true;
private readonly ShaderInstance _drunkShader;
public float CurrentBoozePower = 0.0f;
// Starting phase for the rotation effect.
// Needed so it doesn't always look the same for 0 motion.
public float Phase = 0f;
private const float VisualThreshold = 10.0f;
private const float PowerDivisor = 250.0f;
@ -37,12 +41,22 @@ public sealed class DrunkOverlay : Overlay
private const float BoozePowerScale = 8f;
private float _visualScale = 0;
private float _visualScale = 0f;
private float _timeScale = 1f;
private float _distortionScale = 1f;
public DrunkOverlay()
{
IoCManager.InjectDependencies(this);
_drunkShader = _prototypeManager.Index(Shader).InstanceUnique();
_statusEffectsSystem = _entityManager.System<Shared.StatusEffectNew.StatusEffectsSystem>();
_drunkShader = _prototypeManager.Index(DrunkShader).InstanceUnique();
_configManager.OnValueChanged(CCVars.ReducedMotion, OnReducedMotionChanged, invokeImmediately: true);
}
private void OnReducedMotionChanged(bool reducedMotion)
{
_timeScale = reducedMotion ? 0.0f : 1.0f;
_distortionScale = reducedMotion ? 4.0f : 1.0f; // Make the offset stronger to compensate the lack of motion.
}
protected override void FrameUpdate(FrameEventArgs args)
@ -53,15 +67,14 @@ public sealed class DrunkOverlay : Overlay
if (playerEntity == null)
return;
var statusSys = _sysMan.GetEntitySystem<Shared.StatusEffectNew.StatusEffectsSystem>();
if (!statusSys.TryGetMaxTime<DrunkStatusEffectComponent>(playerEntity.Value, out var status))
if (!_statusEffectsSystem.TryGetMaxTime<DrunkStatusEffectComponent>(playerEntity.Value, out var status))
return;
var time = status.Item2;
var power = time == null ? MaxBoozePower : (float) Math.Min((time - _timing.CurTime).Value.TotalSeconds, MaxBoozePower);
var power = time == null ? MaxBoozePower : (float)Math.Min((time - _timing.CurTime).Value.TotalSeconds, MaxBoozePower);
CurrentBoozePower += BoozePowerScale * (power - CurrentBoozePower) * args.DeltaSeconds / (power+1);
CurrentBoozePower += BoozePowerScale * (power - CurrentBoozePower) * args.DeltaSeconds / (power + 1);
}
protected override bool BeforeDraw(in OverlayDrawArgs args)
@ -82,8 +95,12 @@ public sealed class DrunkOverlay : Overlay
return;
var handle = args.WorldHandle;
_drunkShader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
_drunkShader.SetParameter("boozePower", _visualScale);
_drunkShader.SetParameter("timeScale", _timeScale);
_drunkShader.SetParameter("distortionScale", _distortionScale);
_drunkShader.SetParameter("phase", Phase);
handle.UseShader(_drunkShader);
handle.DrawRect(args.WorldBounds, Color.White);
handle.UseShader(null);

View File

@ -3,6 +3,7 @@ using Content.Shared.StatusEffectNew;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Player;
using Robust.Shared.Random;
namespace Content.Client.Drunk;
@ -10,6 +11,7 @@ public sealed class DrunkSystem : SharedDrunkSystem
{
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IOverlayManager _overlayMan = default!;
[Dependency] private readonly IRobustRandom _random = default!;
private DrunkOverlay _overlay = default!;
@ -29,7 +31,10 @@ public sealed class DrunkSystem : SharedDrunkSystem
private void OnStatusApplied(Entity<DrunkStatusEffectComponent> entity, ref StatusEffectAppliedEvent args)
{
if (!_overlayMan.HasOverlay<DrunkOverlay>())
{
_overlay.Phase = _random.NextFloat(MathF.Tau); // random starting phase for movement effect
_overlayMan.AddOverlay(_overlay);
}
}
private void OnStatusRemoved(Entity<DrunkStatusEffectComponent> entity, ref StatusEffectRemovedEvent args)
@ -47,6 +52,7 @@ public sealed class DrunkSystem : SharedDrunkSystem
private void OnPlayerAttached(Entity<DrunkStatusEffectComponent> entity, ref StatusEffectRelayedEvent<LocalPlayerAttachedEvent> args)
{
_overlayMan.AddOverlay(_overlay);
}
private void OnPlayerDetached(Entity<DrunkStatusEffectComponent> entity, ref StatusEffectRelayedEvent<LocalPlayerDetachedEvent> args)

View File

@ -1,22 +1,29 @@
uniform sampler2D SCREEN_TEXTURE;
uniform highp float boozePower;
const highp float TimeScale = 0.5;
const highp float DistortionScale = 0.01;
// How fast to do the rotating motion.
// 1 for normal effect.
// 0 for for no motion.
uniform highp float timeScale;
// Starting phase for the rotation effect.
// Needed so it doesn't always look the same for 0 motion.
uniform highp float phase;
// Multiplier for the amplitude of the offset. 1 for normal strength.
uniform highp float distortionScale;
void fragment() {
highp float mod = mix(0.0, DistortionScale, boozePower);
highp float amplitudeMod = mix(0.0, distortionScale * 0.01, boozePower);
highp vec2 coord = FRAGCOORD.xy * SCREEN_PIXEL_SIZE.xy;
highp float time = TIME * TimeScale;
highp float time = TIME * timeScale * 0.5 + phase;
highp vec2 offset = vec2((mod * 1.5) * sin(time * 1.5), (mod * 2.0) * cos(time * 1.5 - 0.2));
highp vec2 offset = vec2((amplitudeMod * 1.5) * sin(time * 1.5), (amplitudeMod * 2.0) * cos(time * 1.5 - 0.2));
highp vec4 tex1 = zTextureSpec(SCREEN_TEXTURE, coord + offset);
if (boozePower > 0.5) {
offset = vec2((mod * 2.0 - DistortionScale) * sin(time * 0.333 - 0.2), (mod * 2.0 - DistortionScale) * cos(time * 0.333));
tex1 = mix(tex1, zTextureSpec(SCREEN_TEXTURE, coord + offset), mix(0.0, 0.3, boozePower*2.0-1.0));
if (boozePower > 0.25) {
offset = vec2((amplitudeMod * 2.0) * sin(time * 0.333 - 0.2), (amplitudeMod * 2.0) * cos(time * 0.333));
tex1 = mix(tex1, zTextureSpec(SCREEN_TEXTURE, coord + offset), mix(0.0, 0.3, boozePower * 2.0 - 0.5));
}
offset = vec2((mod * 1.0) * sin(time * 1.0 + 0.1), (mod * 1.0) * cos(time * 1.0));
offset = vec2(amplitudeMod * sin(time * 1.0 + 0.1), amplitudeMod * cos(time * 1.0));
COLOR = mix(tex1, zTextureSpec(SCREEN_TEXTURE, coord + offset), mix(0.0, 0.5, boozePower));
}