]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Refactor SeeingRainbows to new status effect system (#38620)
authorRed <96445749+TheShuEd@users.noreply.github.com>
Fri, 27 Jun 2025 18:19:04 +0000 (21:19 +0300)
committerGitHub <noreply@github.com>
Fri, 27 Jun 2025 18:19:04 +0000 (21:19 +0300)
14 files changed:
Content.Client/Drowsiness/DrowsinessOverlay.cs
Content.Client/Drugs/DrugOverlaySystem.cs
Content.Client/Drugs/RainbowOverlay.cs
Content.Shared/Drugs/SeeingRainbowsComponent.cs
Content.Shared/StatusEffectNew/StatusEffectSystem.API.cs
Resources/Prototypes/Entities/Mobs/Species/base.yml
Resources/Prototypes/Entities/StatusEffects/misc.yml
Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml
Resources/Prototypes/Reagents/cleaning.yml
Resources/Prototypes/Reagents/gases.yml
Resources/Prototypes/Reagents/medicine.yml
Resources/Prototypes/Reagents/narcotics.yml
Resources/Prototypes/Reagents/toxins.yml
Resources/Prototypes/status_effects.yml

index 9705aa73139498554887dfd2df1a8dea8348c04f..1687216b3e1cd35213e3df14fb7473fc64847269 100644 (file)
@@ -1,7 +1,5 @@
-using Content.Shared.Bed.Sleep;
 using Content.Shared.Drowsiness;
 using Content.Shared.StatusEffectNew;
-using Content.Shared.StatusEffectNew.Components;
 using Robust.Client.Graphics;
 using Robust.Client.Player;
 using Robust.Shared.Enums;
@@ -23,8 +21,6 @@ public sealed class DrowsinessOverlay : Overlay
     public override bool RequestScreenTexture => true;
     private readonly ShaderInstance _drowsinessShader;
 
-    private EntityQuery<StatusEffectComponent> _statusQuery;
-
     public float CurrentPower = 0.0f;
 
     private const float PowerDivisor = 250.0f;
@@ -34,9 +30,9 @@ public sealed class DrowsinessOverlay : Overlay
     public DrowsinessOverlay()
     {
         IoCManager.InjectDependencies(this);
+
         _statusEffects = _sysMan.GetEntitySystem<SharedStatusEffectsSystem>();
 
-        _statusQuery = _entityManager.GetEntityQuery<StatusEffectComponent>();
         _drowsinessShader = _prototypeManager.Index<ShaderPrototype>("Drowsiness").InstanceUnique();
     }
 
@@ -47,22 +43,11 @@ public sealed class DrowsinessOverlay : Overlay
         if (playerEntity == null)
             return;
 
-        if (!_statusEffects.TryEffectsWithComp<DrowsinessStatusEffectComponent>(playerEntity, out var drowsinessEffects))
-            return;
-
-        TimeSpan? remainingTime = TimeSpan.Zero;
-        foreach (var (_, _, statusEffectComp) in drowsinessEffects)
-        {
-            if (statusEffectComp.EndEffectTime > remainingTime)
-                remainingTime = statusEffectComp.EndEffectTime;
-        }
-
-        if (remainingTime is null)
+        if (!_statusEffects.TryGetEffectsEndTimeWithComp<DrowsinessStatusEffectComponent>(playerEntity, out var endTime))
             return;
 
-        var curTime = _timing.CurTime;
-        var timeLeft = (float)(remainingTime - curTime).Value.TotalSeconds;
-
+        endTime ??= TimeSpan.MaxValue;
+        var timeLeft = (float)(endTime - _timing.CurTime).Value.TotalSeconds;
         CurrentPower += 8f * (0.5f * timeLeft - CurrentPower) * args.DeltaSeconds / (timeLeft + 1);
     }
 
index 608ae02842888a8206c376007bff80c899aaf3d7..e156e616b8f802082bff1cdb088711ac20704714 100644 (file)
@@ -1,4 +1,5 @@
 using Content.Shared.Drugs;
+using Content.Shared.StatusEffectNew;
 using Robust.Client.Graphics;
 using Robust.Client.Player;
 using Robust.Shared.Player;
@@ -17,49 +18,47 @@ public sealed class DrugOverlaySystem : EntitySystem
 
     private RainbowOverlay _overlay = default!;
 
-    public static string RainbowKey = "SeeingRainbows";
-
     public override void Initialize()
     {
         base.Initialize();
 
-        SubscribeLocalEvent<SeeingRainbowsComponent, ComponentInit>(OnInit);
-        SubscribeLocalEvent<SeeingRainbowsComponent, ComponentShutdown>(OnShutdown);
+        SubscribeLocalEvent<SeeingRainbowsStatusEffectComponent, StatusEffectAppliedEvent>(OnApplied);
+        SubscribeLocalEvent<SeeingRainbowsStatusEffectComponent, StatusEffectRemovedEvent>(OnRemoved);
 
-        SubscribeLocalEvent<SeeingRainbowsComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
-        SubscribeLocalEvent<SeeingRainbowsComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);
+        SubscribeLocalEvent<SeeingRainbowsStatusEffectComponent, StatusEffectRelayedEvent<LocalPlayerAttachedEvent>>(OnPlayerAttached);
+        SubscribeLocalEvent<SeeingRainbowsStatusEffectComponent, StatusEffectRelayedEvent<LocalPlayerDetachedEvent>>(OnPlayerDetached);
 
         _overlay = new();
     }
 
-    private void OnPlayerAttached(EntityUid uid, SeeingRainbowsComponent component, LocalPlayerAttachedEvent args)
+    private void OnRemoved(Entity<SeeingRainbowsStatusEffectComponent> ent, ref StatusEffectRemovedEvent args)
     {
-        _overlayMan.AddOverlay(_overlay);
-    }
+        if (_player.LocalEntity != args.Target)
+            return;
 
-    private void OnPlayerDetached(EntityUid uid, SeeingRainbowsComponent component, LocalPlayerDetachedEvent args)
-    {
         _overlay.Intoxication = 0;
         _overlay.TimeTicker = 0;
         _overlayMan.RemoveOverlay(_overlay);
     }
 
-    private void OnInit(EntityUid uid, SeeingRainbowsComponent component, ComponentInit args)
+    private void OnApplied(Entity<SeeingRainbowsStatusEffectComponent> ent, ref StatusEffectAppliedEvent args)
     {
-        if (_player.LocalEntity == uid)
-        {
-            _overlay.Phase = _random.NextFloat(MathF.Tau); // random starting phase for movement effect
-            _overlayMan.AddOverlay(_overlay);
-        }
+        if (_player.LocalEntity != args.Target)
+            return;
+
+        _overlay.Phase = _random.NextFloat(MathF.Tau); // random starting phase for movement effect
+        _overlayMan.AddOverlay(_overlay);
     }
 
-    private void OnShutdown(EntityUid uid, SeeingRainbowsComponent component, ComponentShutdown args)
+    private void OnPlayerAttached(Entity<SeeingRainbowsStatusEffectComponent> ent, ref StatusEffectRelayedEvent<LocalPlayerAttachedEvent> args)
     {
-        if (_player.LocalEntity == uid)
-        {
-            _overlay.Intoxication = 0;
-            _overlay.TimeTicker = 0;
-            _overlayMan.RemoveOverlay(_overlay);
-        }
+        _overlayMan.AddOverlay(_overlay);
+    }
+
+    private void OnPlayerDetached(Entity<SeeingRainbowsStatusEffectComponent> ent, ref StatusEffectRelayedEvent<LocalPlayerDetachedEvent> args)
+    {
+        _overlay.Intoxication = 0;
+        _overlay.TimeTicker = 0;
+        _overlayMan.RemoveOverlay(_overlay);
     }
 }
index 4e0bed126419e0387b2e25fbe4389ede2d96e73f..bfb3815649929ed075f516cbd666a8b47f7e449b 100644 (file)
@@ -1,6 +1,6 @@
 using Content.Shared.CCVar;
 using Content.Shared.Drugs;
-using Content.Shared.StatusEffect;
+using Content.Shared.StatusEffectNew;
 using Robust.Client.Graphics;
 using Robust.Client.Player;
 using Robust.Shared.Configuration;
@@ -17,6 +17,8 @@ public sealed class RainbowOverlay : Overlay
     [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
     [Dependency] private readonly IPlayerManager _playerManager = default!;
     [Dependency] private readonly IEntitySystemManager _sysMan = default!;
+    [Dependency] private readonly IGameTiming _timing = default!;
+    private readonly SharedStatusEffectsSystem _statusEffects = default!;
 
     public override OverlaySpace Space => OverlaySpace.WorldSpace;
     public override bool RequestScreenTexture => true;
@@ -37,6 +39,8 @@ public sealed class RainbowOverlay : Overlay
     {
         IoCManager.InjectDependencies(this);
 
+        _statusEffects = _sysMan.GetEntitySystem<SharedStatusEffectsSystem>();
+
         _rainbowShader = _prototypeManager.Index<ShaderPrototype>("Rainbow").InstanceUnique();
         _config.OnValueChanged(CCVars.ReducedMotion, OnReducedMotionChanged, invokeImmediately: true);
     }
@@ -54,18 +58,13 @@ public sealed class RainbowOverlay : Overlay
         if (playerEntity == null)
             return;
 
-        if (!_entityManager.HasComponent<SeeingRainbowsComponent>(playerEntity)
-            || !_entityManager.TryGetComponent<StatusEffectsComponent>(playerEntity, out var status))
-            return;
-
-        var statusSys = _sysMan.GetEntitySystem<StatusEffectsSystem>();
-        if (!statusSys.TryGetTime(playerEntity.Value, DrugOverlaySystem.RainbowKey, out var time, status))
+        if (!_statusEffects.TryGetEffectsEndTimeWithComp<SeeingRainbowsStatusEffectComponent>(playerEntity, out var endTime))
             return;
 
-        var timeLeft = (float)(time.Value.Item2 - time.Value.Item1).TotalSeconds;
+        endTime ??= TimeSpan.MaxValue;
+        var timeLeft = (float)(endTime - _timing.CurTime).Value.TotalSeconds;
 
         TimeTicker += args.DeltaSeconds;
-
         if (timeLeft - TimeTicker > timeLeft / 16f)
         {
             Intoxication += (timeLeft - Intoxication) * args.DeltaSeconds / 16f;
index 221599c26e445dba937de5dde5f7e81e70611546..2f22b1dc6a8dc2d38a09a8bf1ef283eb055d8b07 100644 (file)
@@ -3,7 +3,8 @@ using Robust.Shared.GameStates;
 namespace Content.Shared.Drugs;
 
 /// <summary>
-///     Exists for use as a status effect. Adds a shader to the client that scales with the effect duration.
+///  Adds a shader to the client that scales with the effect duration.
+///  Use only in conjunction with <see cref="StatusEffectComponent"/>, on the status effect entity.
 /// </summary>
 [RegisterComponent, NetworkedComponent]
-public sealed partial class SeeingRainbowsComponent : Component { }
+public sealed partial class SeeingRainbowsStatusEffectComponent : Component;
index 14b02dd9db671da9094a7a2d71d4fc811449ac92..2d1ec89c9def0e8535581e0b14a07fec01eccd96 100644 (file)
@@ -269,7 +269,7 @@ public abstract partial class SharedStatusEffectsSystem
 
         foreach (var effect in container.ActiveStatusEffects)
         {
-            if (!TryComp<StatusEffectComponent>(effect, out var statusComp))
+            if (!_effectQuery.TryComp(effect, out var statusComp))
                 continue;
 
             if (TryComp<T>(effect, out var comp))
@@ -279,6 +279,39 @@ public abstract partial class SharedStatusEffectsSystem
             }
         }
 
-        return effects != null;
+        return effects is not null;
+    }
+
+    /// <summary>
+    /// Helper function for calculating how long it takes for all effects with a particular component to disappear. Useful for overlays.
+    /// </summary>
+    /// <param name="target">An entity from which status effects are checked.</param>
+    /// <param name="endTime">The farthest end time of effects with this component is returned. Can be null if one of the effects is infinite.</param>
+    /// <returns>True if effects with the specified component were found, or False if there are no such effects.</returns>
+    public bool TryGetEffectsEndTimeWithComp<T>(EntityUid? target, out TimeSpan? endTime) where T : IComponent
+    {
+        endTime = _timing.CurTime;
+        if (!_containerQuery.TryComp(target, out var container))
+            return false;
+
+        foreach (var effect in container.ActiveStatusEffects)
+        {
+            if (!HasComp<T>(effect))
+                continue;
+
+            if (!_effectQuery.TryComp(effect, out var statusComp))
+                continue;
+
+            if (statusComp.EndEffectTime is null)
+            {
+                endTime = null;
+                return true; //This effect never ends, so we return null at endTime, but return true that there is time.
+            }
+
+            if (statusComp.EndEffectTime > endTime)
+                endTime = statusComp.EndEffectTime;
+        }
+
+        return endTime is not null;
     }
 }
index b93ed915e284e29ea2117e5d8c9a4a0337691602..5bf9a9ede072c23ad75ab480f98444de1fd05bbf 100644 (file)
     - KnockedDown
     - SlowedDown
     - Stutter
-    - SeeingRainbows
     - Electrocution
     - Drunk
     - SlurredSpeech
index bccdea773fbc09416796d76c24bb5b7eba103900..bb2aa9de93b3aeef59a71e09d65e29a81e6516b3 100644 (file)
   name: drowsiness
   components:
   - type: DrowsinessStatusEffect
+
+# Adds drugs overlay
+- type: entity
+  parent: MobStatusEffectBase
+  id: StatusEffectSeeingRainbow
+  name: hallucinations
+  components:
+  - type: SeeingRainbowsStatusEffect
\ No newline at end of file
index adb9aa28e4a2b472a4ee5a4da0d6cc74c3889058..741108cca1e8bbf0e0889c52dfd11ddd06e2bceb 100644 (file)
       - !type:AdjustReagent
         reagent: Ethanol
         amount: 0.05
-      - !type:GenericStatusEffect
+      - !type:ModifyStatusEffect
+        effectProto: StatusEffectSeeingRainbow
         conditions:
         - !type:ReagentThreshold
           min: 10
-        key: SeeingRainbows
-        component: SeeingRainbows
         type: Add
         time: 5
         refresh: false
index b9a0af01de835a8af1ac0be10b1fab6f2285432a..33c0a0e86f61af07460b79c4f0a43c29e2e40b83 100644 (file)
   metabolisms:
     Narcotic:
       effects:
-      - !type:GenericStatusEffect
-        key: SeeingRainbows
-        component: SeeingRainbows
-        type: Add
+      - !type:ModifyStatusEffect
+        effectProto: StatusEffectSeeingRainbow
         time: 5
+        type: Add
         refresh: false
     Drink:
       effects:
index 1087d7bad4cd5e2499f7b7bd6de227b6f8238b79..4a97cb8b167cf9784471aaa23213baab90958d12 100644 (file)
         damage:
           types:
             Cellular: 1
-      - !type:GenericStatusEffect
-        key: SeeingRainbows
-        component: SeeingRainbows
+      - !type:ModifyStatusEffect
+        effectProto: StatusEffectSeeingRainbow
         type: Add
         time: 15
         refresh: false
         damage:
           types:
             Cellular: 0.5
-      - !type:GenericStatusEffect
+      - !type:ModifyStatusEffect
         conditions:
         - !type:ReagentThreshold
           reagent: Frezon
           min: 1
-        key: SeeingRainbows
-        component: SeeingRainbows
+        effectProto: StatusEffectSeeingRainbow
         type: Add
         time: 500
         refresh: false
index 2873372b52d77611d9c94cc086f900792da86811..dfecb112d545a0fbd7f3f8e5409af0ec33866925 100644 (file)
         key: KnockedDown
         time: 3.0
         type: Remove
-      - !type:GenericStatusEffect
-        key: SeeingRainbows
+      - !type:ModifyStatusEffect
+        effectProto: StatusEffectSeeingRainbow
         time: 15.0
         type: Remove
 
         damage:
           types:
             Poison: 2
-      - !type:GenericStatusEffect
+      - !type:ModifyStatusEffect
+        effectProto: StatusEffectSeeingRainbow
         conditions:
         - !type:ReagentThreshold
           min: 30
-        key: SeeingRainbows
-        component: SeeingRainbows
         type: Add
         time: 8
         refresh: false
         key: Jitter
         time: 4.0
         type: Remove
-      - !type:GenericStatusEffect
-        key: SeeingRainbows
+      - !type:ModifyStatusEffect
+        effectProto: StatusEffectSeeingRainbow
         time: 10.0
         type: Remove
       - !type:AdjustReagent
index aff87479b1e1f076ad202f343365a5a98a3943b9..ed8b8acc65bd03bf82ff27a17e3aaa7a163cad3f 100644 (file)
   metabolisms:
     Narcotic:
       effects:
-      - !type:GenericStatusEffect
-        key: SeeingRainbows
-        component: SeeingRainbows
-        type: Add
+      - !type:ModifyStatusEffect
+        effectProto: StatusEffectSeeingRainbow
         time: 16
+        type: Add
         refresh: false
 
 - type: reagent
         damage:
           types:
             Poison: 2
-      - !type:GenericStatusEffect
-        key: SeeingRainbows
-        component: SeeingRainbows
-        type: Add
+      - !type:ModifyStatusEffect
+        effectProto: StatusEffectSeeingRainbow
         time: 10
+        type: Add
         refresh: false
       - !type:ChemVomit # Vomiting is a symptom of brain damage
         probability: 0.05
   metabolisms:
     Narcotic:
       effects:
-      - !type:GenericStatusEffect
-        key: SeeingRainbows
-        component: SeeingRainbows
+      - !type:ModifyStatusEffect
+        effectProto: StatusEffectSeeingRainbow
         type: Add
         time: 5
         refresh: false
   metabolisms:
     Narcotic:
       effects:
-      - !type:GenericStatusEffect
-        key: SeeingRainbows
-        component: SeeingRainbows
+      - !type:ModifyStatusEffect
+        effectProto: StatusEffectSeeingRainbow
         type: Add
         time: 5
         refresh: false
         conditions:
         - !type:ReagentThreshold
           max: 20
-      - !type:GenericStatusEffect
-        key: SeeingRainbows
-        component: SeeingRainbows
+      - !type:ModifyStatusEffect
+        effectProto: StatusEffectSeeingRainbow
         type: Add
         time: 5
         refresh: false
index 6560f05995a3ea3980e65e7bd6c7dabef5bce4bc..96761ae778be628d69c66803e3d038d9746ee804 100644 (file)
   metabolisms:
     Poison:
       effects:
-      - !type:GenericStatusEffect
-        key: SeeingRainbows
-        component: SeeingRainbows
+      - !type:ModifyStatusEffect
+        effectProto: StatusEffectSeeingRainbow
         type: Add
         time: 10
         refresh: false
index e98dd4df02b17a4e0fc0efa45da2de787f4bbd55..7c96b88c22d19d48acf81e7da5b3c771c2287dfb 100644 (file)
@@ -25,9 +25,6 @@
 - type: statusEffect
   id: AllCaps
 
-- type: statusEffect
-  id: SeeingRainbows
-
 - type: statusEffect
   id: Electrocution