]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Space cleaner buffs (#15779)
authormetalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Mon, 1 May 2023 14:25:33 +0000 (00:25 +1000)
committerGitHub <noreply@github.com>
Mon, 1 May 2023 14:25:33 +0000 (00:25 +1000)
Content.Client/Chemistry/Visualizers/VaporVisualizerSystem.cs
Content.Server/Chemistry/EntitySystems/VaporSystem.cs
Content.Server/Chemistry/TileReactions/CleanDecalsReaction.cs [new file with mode: 0644]
Content.Server/Chemistry/TileReactions/CleanTileReaction.cs
Content.Server/Cleanable/CleanableComponent.cs [deleted file]
Content.Server/Fluids/Components/SprayComponent.cs
Content.Server/Fluids/EntitySystems/SpraySystem.cs
Content.Shared/Vapor/SharedVaporComponent.cs
Resources/Prototypes/Entities/Objects/Specific/Janitorial/spray.yml
Resources/Prototypes/Reagents/cleaning.yml
Resources/Prototypes/Reagents/fun.yml

index 42e8f40f9a9c713b778aa518776424b4ebc9c257..6c086198dbc9da6f0b75a984af298ec81140b2d4 100644 (file)
@@ -35,6 +35,14 @@ public sealed class VaporVisualizerSystem : VisualizerSystem<VaporVisualsCompone
                 }
             }
         };
+
+        if (AppearanceSystem.TryGetData<bool>(uid, VaporVisuals.State, out var state) &&
+            state &&
+            TryComp<AnimationPlayerComponent>(uid, out var animPlayer) &&
+            !AnimationSystem.HasRunningAnimation(uid, animPlayer, VaporVisualsComponent.AnimationKey))
+        {
+            AnimationSystem.Play(uid, animPlayer, comp.VaporFlick, VaporVisualsComponent.AnimationKey);
+        }
     }
 
     /// <summary>
@@ -46,13 +54,6 @@ public sealed class VaporVisualizerSystem : VisualizerSystem<VaporVisualsCompone
         {
             args.Sprite.Color = color;
         }
-
-        if ((AppearanceSystem.TryGetData<bool>(uid, VaporVisuals.State, out var state, args.Component) && state) &&
-            TryComp<AnimationPlayerComponent>(uid, out var animPlayer) &&
-           !AnimationSystem.HasRunningAnimation(uid, animPlayer, VaporVisualsComponent.AnimationKey))
-        {
-            AnimationSystem.Play(uid, animPlayer, comp.VaporFlick, VaporVisualsComponent.AnimationKey);
-        }
     }
 }
 
index 106867ccbc6eec4db83168c1034ff3b9d0ca2d74..38e22ad14e9dfd98c1d597a85bbf8ace330a020e 100644 (file)
@@ -63,7 +63,7 @@ namespace Content.Server.Chemistry.EntitySystems
                 _physics.SetLinearDamping(physics, 0f);
                 _physics.SetAngularDamping(physics, 0f);
 
-                _throwing.TryThrow(vapor.Owner, dir * speed, speed, user: user, pushbackRatio: 50f);
+                _throwing.TryThrow(vapor.Owner, dir, speed, user: user, pushbackRatio: 50f);
 
                 var distance = (target.Position - vaporXform.WorldPosition).Length;
                 var time = (distance / physics.LinearVelocity.Length);
diff --git a/Content.Server/Chemistry/TileReactions/CleanDecalsReaction.cs b/Content.Server/Chemistry/TileReactions/CleanDecalsReaction.cs
new file mode 100644 (file)
index 0000000..0ae41d3
--- /dev/null
@@ -0,0 +1,55 @@
+using Content.Server.Decals;
+using Content.Shared.Chemistry.Reaction;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.Decals;
+using Content.Shared.FixedPoint;
+using Robust.Shared.Map;
+using Robust.Shared.Map.Components;
+
+namespace Content.Server.Chemistry.TileReactions;
+
+/// <summary>
+/// Purges all cleanable decals on a tile.
+/// </summary>
+[DataDefinition]
+public sealed class CleanDecalsReaction : ITileReaction
+{
+    /// <summary>
+    /// For every cleaned decal we lose this much reagent.
+    /// </summary>
+    [DataField("cleanCost")]
+    public FixedPoint2 CleanCost { get; private set; } = FixedPoint2.New(0.25f);
+
+    public FixedPoint2 TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume)
+    {
+        var entMan = IoCManager.Resolve<IEntityManager>();
+
+        if (reactVolume <= CleanCost ||
+            !entMan.TryGetComponent<MapGridComponent>(tile.GridUid, out var grid) ||
+            !entMan.TryGetComponent<DecalGridComponent>(tile.GridUid, out var decalGrid))
+        {
+            return FixedPoint2.Zero;
+        }
+
+        var lookupSystem = entMan.System<EntityLookupSystem>();
+        var decalSystem = entMan.System<DecalSystem>();
+        // Very generous hitbox.
+        var decals = decalSystem
+            .GetDecalsIntersecting(tile.GridUid, lookupSystem.GetLocalBounds(tile, grid.TileSize).Enlarged(0.5f).Translated(new Vector2(-0.5f, -0.5f)));
+        var amount = FixedPoint2.Zero;
+
+        foreach (var decal in decals)
+        {
+            if (!decal.Decal.Cleanable)
+                continue;
+
+            decalSystem.RemoveDecal(tile.GridUid, decal.Index, decalGrid);
+            amount += CleanCost;
+
+            if (amount > reactVolume)
+                break;
+        }
+
+        return amount;
+    }
+}
index bf3ab310ad7f1dc68d71830a4b38530f436df22d..a2bd5decbda8bf59dd0c806a14feb2c140147cf2 100644 (file)
@@ -1,50 +1,64 @@
 using System.Linq;
-using Content.Server.Cleanable;
-using Content.Server.Decals;
+using Content.Server.Chemistry.EntitySystems;
+using Content.Shared.Chemistry.Components;
 using Content.Shared.Chemistry.Reaction;
 using Content.Shared.Chemistry.Reagent;
 using Content.Shared.FixedPoint;
+using Content.Shared.Fluids.Components;
 using Robust.Shared.Map;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
 
-namespace Content.Server.Chemistry.TileReactions
+namespace Content.Server.Chemistry.TileReactions;
+
+/// <summary>
+/// Turns all of the reagents on a puddle into water.
+/// </summary>
+[DataDefinition]
+public sealed class CleanTileReaction : ITileReaction
 {
-    [DataDefinition]
-    public sealed class CleanTileReaction : ITileReaction
+    /// <summary>
+    /// How much it costs to clean 1 unit of reagent.
+    /// </summary>
+    /// <remarks>
+    /// In terms of space cleaner can clean 1 average puddle per 5 units.
+    /// </remarks>
+    [DataField("cleanCost")]
+    public float CleanAmountMultiplier { get; private set; } = 0.25f;
+
+    /// <summary>
+    /// What reagent to replace the tile conents with.
+    /// </summary>
+    [DataField("reagent", customTypeSerializer:typeof(PrototypeIdSerializer<ReagentPrototype>))]
+    public string ReplacementReagent = "Water";
+
+    FixedPoint2 ITileReaction.TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume)
     {
-        /// <summary>
-        ///     Multiplier used in CleanTileReaction.
-        ///     1 (default) means normal consumption rate of the cleaning reagent.
-        ///     0 means no consumption of the cleaning reagent, i.e. the reagent is inexhaustible.
-        /// </summary>
-        [DataField("cleanAmountMultiplier")]
-        public float CleanAmountMultiplier { get; private set; } = 1.0f;
-
-        FixedPoint2 ITileReaction.TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume)
+        var entMan = IoCManager.Resolve<IEntityManager>();
+        var entities = entMan.System<EntityLookupSystem>().GetEntitiesIntersecting(tile).ToArray();
+        var puddleQuery = entMan.GetEntityQuery<PuddleComponent>();
+        var solutionContainerSystem = entMan.System<SolutionContainerSystem>();
+        // Multiply as the amount we can actually purge is higher than the react amount.
+        var purgeAmount = reactVolume / CleanAmountMultiplier;
+
+        foreach (var entity in entities)
         {
-            var entities = EntitySystem.Get<EntityLookupSystem>().GetEntitiesIntersecting(tile).ToArray();
-            var amount = FixedPoint2.Zero;
-            var entMan = IoCManager.Resolve<IEntityManager>();
-            foreach (var entity in entities)
+            if (!puddleQuery.TryGetComponent(entity, out var puddle) ||
+                !solutionContainerSystem.TryGetSolution(entity, puddle.SolutionName, out var puddleSolution))
             {
-                if (entMan.TryGetComponent(entity, out CleanableComponent? cleanable))
-                {
-                    var next = amount + (cleanable.CleanAmount * CleanAmountMultiplier);
-                    // Nothing left?
-                    if (reactVolume < next)
-                        break;
-
-                    amount = next;
-                    entMan.QueueDeleteEntity(entity);
-                }
+                continue;
             }
 
-            var decalSystem = EntitySystem.Get<DecalSystem>();
-            foreach (var (uid, _) in decalSystem.GetDecalsInRange(tile.GridUid, tile.GridIndices+new Vector2(0.5f, 0.5f), validDelegate: x => x.Cleanable))
-            {
-                decalSystem.RemoveDecal(tile.GridUid, uid);
-            }
+            var purgeable =
+                solutionContainerSystem.SplitSolutionWithout(entity, puddleSolution, purgeAmount, ReplacementReagent, reagent.ID);
+
+            purgeAmount -= purgeable.Volume;
 
-            return amount;
+            solutionContainerSystem.TryAddSolution(entity, puddleSolution, new Solution(ReplacementReagent, purgeable.Volume));
+
+            if (purgeable.Volume <= FixedPoint2.Zero)
+                break;
         }
+
+        return (reactVolume / CleanAmountMultiplier - purgeAmount) * CleanAmountMultiplier;
     }
 }
diff --git a/Content.Server/Cleanable/CleanableComponent.cs b/Content.Server/Cleanable/CleanableComponent.cs
deleted file mode 100644 (file)
index 210bc15..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-using Content.Shared.FixedPoint;
-
-namespace Content.Server.Cleanable
-{
-    [RegisterComponent]
-    public sealed class CleanableComponent : Component
-    {
-        [DataField("cleanAmount")]
-        private FixedPoint2 _cleanAmount = FixedPoint2.Zero;
-        [ViewVariables(VVAccess.ReadWrite)]
-        public FixedPoint2 CleanAmount => _cleanAmount;
-    }
-}
index 8ba5f82d8ce5a53bd37b8a5103cf6bf4a405a8ce..0c2848de0632ed055f5967ce4bd1b3698d4cd24e 100644 (file)
@@ -12,26 +12,22 @@ public sealed class SprayComponent : Component
 {
     public const string SolutionName = "spray";
 
-    [DataField("sprayDistance")] public float SprayDistance = 3f;
+    [ViewVariables(VVAccess.ReadWrite), DataField("sprayDistance")]
+    public float SprayDistance = 3.5f;
 
-    [DataField("transferAmount")] public FixedPoint2 TransferAmount = FixedPoint2.New(10);
+    [ViewVariables(VVAccess.ReadWrite), DataField("sprayVelocity")]
+    public float SprayVelocity = 3.5f;
 
-    [DataField("sprayVelocity")] public float SprayVelocity = 1.5f;
-
-    [DataField("sprayAliveTime")] public float SprayAliveTime = 0.75f;
-
-    [DataField("cooldownTime")] public float CooldownTime = 0.5f;
-
-    [DataField("sprayedPrototype", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
+    [ViewVariables(VVAccess.ReadWrite), DataField("sprayedPrototype", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
     public string SprayedPrototype = "Vapor";
 
-    [DataField("vaporAmount")] public int VaporAmount = 1;
-
-    [DataField("vaporSpread")] public float VaporSpread = 90f;
+    [ViewVariables(VVAccess.ReadWrite), DataField("vaporAmount")]
+    public int VaporAmount = 1;
 
-    [DataField("impulse")] public float Impulse;
+    [ViewVariables(VVAccess.ReadWrite), DataField("vaporSpread")]
+    public float VaporSpread = 90f;
 
-    [DataField("spraySound", required: true)]
+    [ViewVariables(VVAccess.ReadWrite), DataField("spraySound", required: true)]
     [Access(typeof(SpraySystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
     public SoundSpecifier SpraySound { get; } = default!;
 }
index 5ba11b5dd3f28abf7dd2bb4b5bf0be48bd23b828..4e7892d8979de4f51a3a0ea5246c35e16766bad4 100644 (file)
@@ -4,6 +4,7 @@ using Content.Server.Cooldown;
 using Content.Server.Extinguisher;
 using Content.Server.Fluids.Components;
 using Content.Server.Popups;
+using Content.Shared.Chemistry.Components;
 using Content.Shared.Cooldown;
 using Content.Shared.FixedPoint;
 using Content.Shared.Interaction;
@@ -50,7 +51,9 @@ public sealed class SpraySystem : EntitySystem
         var curTime = _gameTiming.CurTime;
         if (TryComp<ItemCooldownComponent>(uid, out var cooldown)
             && curTime < cooldown.CooldownEnd)
+        {
             return;
+        }
 
         if (solution.Volume <= 0)
         {
@@ -59,26 +62,37 @@ public sealed class SpraySystem : EntitySystem
             return;
         }
 
+        if (!TryComp<SolutionTransferComponent>(uid, out var transfer))
+            return;
+
         var xformQuery = GetEntityQuery<TransformComponent>();
         var userXform = xformQuery.GetComponent(args.User);
 
         var userMapPos = userXform.MapPosition;
-        var clickMapPos = args.ClickLocation.ToMap(EntityManager);
+        var clickMapPos = args.ClickLocation.ToMap(EntityManager, _transform);
 
         var diffPos = clickMapPos.Position - userMapPos.Position;
         if (diffPos == Vector2.Zero || diffPos == Vector2.NaN)
             return;
 
-        var diffLength = diffPos.Length;
         var diffNorm = diffPos.Normalized;
+        var diffLength = diffPos.Length;
+
+        if (diffLength > component.SprayDistance)
+        {
+            diffLength = component.SprayDistance;
+        }
+
         var diffAngle = diffNorm.ToAngle();
 
         // Vectors to determine the spawn offset of the vapor clouds.
         var threeQuarters = diffNorm * 0.75f;
         var quarter = diffNorm * 0.25f;
 
-        var amount = Math.Max(Math.Min((solution.Volume / component.TransferAmount).Int(), component.VaporAmount), 1);
+        var amount = Math.Max(Math.Min((solution.Volume / transfer.TransferAmount).Int(), component.VaporAmount), 1);
         var spread = component.VaporSpread / amount;
+        // TODO: Just use usedelay homie.
+        var cooldownTime = 0f;
 
         for (var i = 0; i < amount; i++)
         {
@@ -89,11 +103,11 @@ public sealed class SpraySystem : EntitySystem
             var target = userMapPos
                 .Offset((diffNorm + rotation.ToVec()).Normalized * diffLength + quarter);
 
-            var distance = target.Position.Length;
+            var distance = (target.Position - userMapPos.Position).Length;
             if (distance > component.SprayDistance)
                 target = userMapPos.Offset(diffNorm * component.SprayDistance);
 
-            var newSolution = _solutionContainer.SplitSolution(uid, solution, component.TransferAmount);
+            var newSolution = _solutionContainer.SplitSolution(uid, solution, transfer.TransferAmount);
 
             if (newSolution.Volume <= FixedPoint2.Zero)
                 break;
@@ -117,13 +131,16 @@ public sealed class SpraySystem : EntitySystem
 
             // impulse direction is defined in world-coordinates, not local coordinates
             var impulseDirection = rotation.ToVec();
-            _vapor.Start(vaporComponent, vaporXform, impulseDirection, component.SprayVelocity, target, component.SprayAliveTime, args.User);
+            var time = diffLength / component.SprayVelocity;
+            cooldownTime = MathF.Max(time, cooldownTime);
+
+            _vapor.Start(vaporComponent, vaporXform, impulseDirection * diffLength, component.SprayVelocity, target, time, args.User);
         }
 
         _audio.PlayPvs(component.SpraySound, uid, component.SpraySound.Params.WithVariation(0.125f));
 
         RaiseLocalEvent(uid,
-            new RefreshItemCooldownEvent(curTime, curTime + TimeSpan.FromSeconds(component.CooldownTime)), true);
+            new RefreshItemCooldownEvent(curTime, curTime + TimeSpan.FromSeconds(cooldownTime)), true);
     }
 }
 
index 83ad35757ee50ffad5560797dd9c436f26260638..43c65f4959f143e15b73f5ef63c63ec129a7f10b 100644 (file)
@@ -1,12 +1,10 @@
 using Robust.Shared.Serialization;
 
-namespace Content.Shared.Vapor
+namespace Content.Shared.Vapor;
+
+[Serializable, NetSerializable]
+public enum VaporVisuals
 {
-    [Serializable, NetSerializable]
-    public enum VaporVisuals
-    {
-        Rotation,
-        Color,
-        State,
-    }
+    Color,
+    State,
 }
index 8106e170a7d0fc338783cd8f1823d9db1d308c96..6850a4585a42d8a41489f89959c37a24e098bffd 100644 (file)
@@ -27,7 +27,6 @@
     canChangeTransferAmount: true
   - type: ItemCooldown
   - type: Spray
-    transferAmount: 10
     sprayVelocity: 2
     spraySound:
       path: /Audio/Effects/spray2.ogg
@@ -51,9 +50,8 @@
         maxVol: 250
   - type: Spray
     sprayedPrototype: BigVapor
-    transferAmount: 10
     sprayVelocity: 5
-    sprayAliveTime: 1.5
+    sprayAliveTime: 5
     spraySound:
       path: /Audio/Effects/spray2.ogg
 
index 7c297f4b50e7dd82eb7a33d7733afdb36fe461ed..a254af42829e8fcf2d5ab6f56971ba09fe83394e 100644 (file)
@@ -31,6 +31,7 @@
   meltingPoint: -11.0
   tileReactions:
     - !type:CleanTileReaction {}
+    - !type:CleanDecalsReaction {}
 
 - type: reagent
   id: SpaceLube
index 758ed5df9321908c59730f1eb1f4f98fb2dcd1fe..044f9206b5e5ca370731a297b5fddad6edd2b4d3 100644 (file)
@@ -52,7 +52,7 @@
     maxOnTileWhitelist:
       tags: [ Bee ]
   - !type:CleanTileReaction # Bees are extremely obsessive about cleanliness within what they consider their hive.
-    cleanAmountMultiplier: 0 # Consume absolutely zero bees. Buzz buzz.
+    cleanCost: 0 # Consume absolutely zero bees. Buzz buzz.
   metabolisms:
     Poison:
       effects: