RainbowOverlay.cs 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. using Content.Shared.CCVar;
  2. using Content.Shared.Drugs;
  3. using Content.Shared.StatusEffect;
  4. using Robust.Client.Graphics;
  5. using Robust.Client.Player;
  6. using Robust.Shared.Configuration;
  7. using Robust.Shared.Enums;
  8. using Robust.Shared.Prototypes;
  9. using Robust.Shared.Timing;
  10. namespace Content.Client.Drugs;
  11. public sealed class RainbowOverlay : Overlay
  12. {
  13. [Dependency] private readonly IConfigurationManager _config = default!;
  14. [Dependency] private readonly IEntityManager _entityManager = default!;
  15. [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
  16. [Dependency] private readonly IPlayerManager _playerManager = default!;
  17. [Dependency] private readonly IEntitySystemManager _sysMan = default!;
  18. public override OverlaySpace Space => OverlaySpace.WorldSpace;
  19. public override bool RequestScreenTexture => true;
  20. private readonly ShaderInstance _rainbowShader;
  21. public float Intoxication = 0.0f;
  22. public float TimeTicker = 0.0f;
  23. private const float VisualThreshold = 10.0f;
  24. private const float PowerDivisor = 250.0f;
  25. private float EffectScale => Math.Clamp((Intoxication - VisualThreshold) / PowerDivisor, 0.0f, 1.0f);
  26. public RainbowOverlay()
  27. {
  28. IoCManager.InjectDependencies(this);
  29. _rainbowShader = _prototypeManager.Index<ShaderPrototype>("Rainbow").InstanceUnique();
  30. }
  31. protected override void FrameUpdate(FrameEventArgs args)
  32. {
  33. var playerEntity = _playerManager.LocalEntity;
  34. if (playerEntity == null)
  35. return;
  36. if (!_entityManager.HasComponent<SeeingRainbowsComponent>(playerEntity)
  37. || !_entityManager.TryGetComponent<StatusEffectsComponent>(playerEntity, out var status))
  38. return;
  39. var statusSys = _sysMan.GetEntitySystem<StatusEffectsSystem>();
  40. if (!statusSys.TryGetTime(playerEntity.Value, DrugOverlaySystem.RainbowKey, out var time, status))
  41. return;
  42. var timeLeft = (float) (time.Value.Item2 - time.Value.Item1).TotalSeconds;
  43. TimeTicker += args.DeltaSeconds;
  44. if (timeLeft - TimeTicker > timeLeft / 16f)
  45. {
  46. Intoxication += (timeLeft - Intoxication) * args.DeltaSeconds / 16f;
  47. }
  48. else
  49. {
  50. Intoxication -= Intoxication/(timeLeft - TimeTicker) * args.DeltaSeconds;
  51. }
  52. }
  53. protected override bool BeforeDraw(in OverlayDrawArgs args)
  54. {
  55. if (!_entityManager.TryGetComponent(_playerManager.LocalEntity, out EyeComponent? eyeComp))
  56. return false;
  57. if (args.Viewport.Eye != eyeComp.Eye)
  58. return false;
  59. return EffectScale > 0;
  60. }
  61. protected override void Draw(in OverlayDrawArgs args)
  62. {
  63. // TODO disable only the motion part or ike's idea (single static frame of the overlay)
  64. if (_config.GetCVar(CCVars.ReducedMotion))
  65. return;
  66. if (ScreenTexture == null)
  67. return;
  68. var handle = args.WorldHandle;
  69. _rainbowShader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
  70. _rainbowShader.SetParameter("effectScale", EffectScale);
  71. handle.UseShader(_rainbowShader);
  72. handle.DrawRect(args.WorldBounds, Color.White);
  73. handle.UseShader(null);
  74. }
  75. }