diff --git a/Content.Client/Fluids/PuddleSystem.cs b/Content.Client/Fluids/PuddleSystem.cs
index 1ab1ded3e8e..ab96d24d85a 100644
--- a/Content.Client/Fluids/PuddleSystem.cs
+++ b/Content.Client/Fluids/PuddleSystem.cs
@@ -73,7 +73,19 @@ public sealed class PuddleSystem : SharedPuddleSystem
// Maybe someday we'll have clientside prediction for entity spawning, but not today.
// Until then, these methods do nothing on the client.
///
- public override bool TrySplashSpillAt(EntityUid uid, EntityCoordinates coordinates, Solution solution, out EntityUid puddleUid, bool sound = true, EntityUid? user = null)
+ public override bool TrySplashSpillAt(Entity entity, EntityCoordinates coordinates, out EntityUid puddleUid, out Solution solution, bool sound = true, EntityUid? user = null)
+ {
+ puddleUid = EntityUid.Invalid;
+ solution = new Solution();
+ return false;
+ }
+
+ public override bool TrySplashSpillAt(EntityUid entity,
+ EntityCoordinates coordinates,
+ Solution spilled,
+ out EntityUid puddleUid,
+ bool sound = true,
+ EntityUid? user = null)
{
puddleUid = EntityUid.Invalid;
return false;
diff --git a/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs
index ff050ce2cda..ad34f05edd0 100644
--- a/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs
+++ b/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs
@@ -1,42 +1,38 @@
-using Content.Shared.Chemistry.EntitySystems;
using Content.Server.Fluids.EntitySystems;
-using Content.Shared.Fluids.Components;
+using Content.Shared.Chemistry.EntitySystems;
using JetBrains.Annotations;
-namespace Content.Server.Destructible.Thresholds.Behaviors
+namespace Content.Server.Destructible.Thresholds.Behaviors;
+
+[UsedImplicitly]
+[DataDefinition]
+public sealed partial class SpillBehavior : IThresholdBehavior
{
- [UsedImplicitly]
- [DataDefinition]
- public sealed partial class SpillBehavior : IThresholdBehavior
+ ///
+ /// Optional fallback solution name if SpillableComponent is not present.
+ ///
+ [DataField]
+ public string? Solution;
+
+ ///
+ /// When triggered, spills the entity's solution onto the ground.
+ /// Will first try to use the solution from a SpillableComponent if present,
+ /// otherwise falls back to the solution specified in the behavior's data fields.
+ /// The solution is properly drained/split before spilling to prevent double-spilling with other behaviors.
+ ///
+ /// Entity whose solution will be spilled
+ /// System calling this behavior
+ /// Optional entity that caused this behavior to trigger
+ public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
{
- [DataField]
- public string? Solution;
+ var puddleSystem = system.EntityManager.System();
+ var solutionContainer = system.EntityManager.System();
+ var coordinates = system.EntityManager.GetComponent(owner).Coordinates;
- ///
- /// If there is a SpillableComponent on EntityUidowner use it to create a puddle/smear.
- /// Or whatever solution is specified in the behavior itself.
- /// If none are available do nothing.
- ///
- /// Entity on which behavior is executed
- /// system calling the behavior
- ///
- public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
- {
- var solutionContainerSystem = system.EntityManager.System();
- var spillableSystem = system.EntityManager.System();
-
- var coordinates = system.EntityManager.GetComponent(owner).Coordinates;
-
- if (system.EntityManager.TryGetComponent(owner, out SpillableComponent? spillableComponent) &&
- solutionContainerSystem.TryGetSolution(owner, spillableComponent.SolutionName, out _, out var compSolution))
- {
- spillableSystem.TrySplashSpillAt(owner, coordinates, compSolution, out _, false, user: cause);
- }
- else if (Solution != null &&
- solutionContainerSystem.TryGetSolution(owner, Solution, out _, out var behaviorSolution))
- {
- spillableSystem.TrySplashSpillAt(owner, coordinates, behaviorSolution, out _, user: cause);
- }
- }
+ // Spill the solution that was drained/split
+ if (solutionContainer.TryGetSolution(owner, Solution, out _, out var solution))
+ puddleSystem.TrySplashSpillAt(owner, coordinates, solution, out _, false, cause);
+ else
+ puddleSystem.TrySplashSpillAt(owner, coordinates, out _, out _, false, cause);
}
}
diff --git a/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs b/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs
index 01526d4ee5a..e632d6efb32 100644
--- a/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs
+++ b/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs
@@ -29,23 +29,14 @@ public sealed partial class PuddleSystem
private void SpillOnLand(Entity entity, ref LandEvent args)
{
- if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out var soln, out var solution))
+ if (!entity.Comp.SpillWhenThrown || Openable.IsClosed(entity.Owner))
return;
- if (Openable.IsClosed(entity.Owner))
- return;
-
- if (!entity.Comp.SpillWhenThrown)
- return;
-
- if (args.User != null)
+ if (TrySplashSpillAt(entity.Owner, Transform(entity).Coordinates, out _, out var solution) && args.User != null)
{
AdminLogger.Add(LogType.Landed,
$"{ToPrettyString(entity.Owner):entity} spilled a solution {SharedSolutionContainerSystem.ToPrettyString(solution):solution} on landing");
}
-
- var drainedSolution = _solutionContainerSystem.Drain(entity.Owner, soln.Value, solution.Volume);
- TrySplashSpillAt(entity.Owner, Transform(entity).Coordinates, drainedSolution, out _);
}
private void OnDoAfter(Entity entity, ref SpillDoAfterEvent args)
diff --git a/Content.Server/Fluids/EntitySystems/PuddleSystem.cs b/Content.Server/Fluids/EntitySystems/PuddleSystem.cs
index 2f966354eca..c756a8e6963 100644
--- a/Content.Server/Fluids/EntitySystems/PuddleSystem.cs
+++ b/Content.Server/Fluids/EntitySystems/PuddleSystem.cs
@@ -369,16 +369,37 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
// TODO: This can be predicted once https://github.com/space-wizards/RobustToolbox/pull/5849 is merged
///
- public override bool TrySplashSpillAt(EntityUid uid,
+ public override bool TrySplashSpillAt(Entity entity,
EntityCoordinates coordinates,
- Solution solution,
+ out EntityUid puddleUid,
+ out Solution spilled,
+ bool sound = true,
+ EntityUid? user = null)
+ {
+ puddleUid = EntityUid.Invalid;
+ spilled = new Solution();
+
+ if (!Resolve(entity, ref entity.Comp))
+ return false;
+
+ if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out var solution))
+ return false;
+
+ spilled = solution.Value.Comp.Solution;
+
+ return TrySplashSpillAt(entity, coordinates, spilled, out puddleUid, sound, user);
+ }
+
+ public override bool TrySplashSpillAt(EntityUid entity,
+ EntityCoordinates coordinates,
+ Solution spilled,
out EntityUid puddleUid,
bool sound = true,
EntityUid? user = null)
{
puddleUid = EntityUid.Invalid;
- if (solution.Volume == 0)
+ if (spilled.Volume == 0)
return false;
var targets = new List();
@@ -392,26 +413,28 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
var owner = ent.Owner;
// between 5 and 30%
- var splitAmount = solution.Volume * _random.NextFloat(0.05f, 0.30f);
- var splitSolution = solution.SplitSolution(splitAmount);
+ var splitAmount = spilled.Volume * _random.NextFloat(0.05f, 0.30f);
+ var splitSolution = spilled.SplitSolution(splitAmount);
if (user != null)
{
AdminLogger.Add(LogType.Landed,
- $"{ToPrettyString(user.Value):user} threw {ToPrettyString(uid):entity} which splashed a solution {SharedSolutionContainerSystem.ToPrettyString(solution):solution} onto {ToPrettyString(owner):target}");
+ $"{ToPrettyString(user.Value):user} threw {ToPrettyString(entity):entity} which splashed a solution {SharedSolutionContainerSystem.ToPrettyString(spilled):solution} onto {ToPrettyString(owner):target}");
}
targets.Add(owner);
Reactive.DoEntityReaction(owner, splitSolution, ReactionMethod.Touch);
- Popups.PopupEntity(
- Loc.GetString("spill-land-spilled-on-other", ("spillable", uid),
- ("target", Identity.Entity(owner, EntityManager))), owner, PopupType.SmallCaution);
+ Popups.PopupEntity(Loc.GetString("spill-land-spilled-on-other",
+ ("spillable", entity),
+ ("target", Identity.Entity(owner, EntityManager))),
+ owner,
+ PopupType.SmallCaution);
}
- _color.RaiseEffect(solution.GetColor(_prototypeManager), targets,
- Filter.Pvs(uid, entityManager: EntityManager));
+ _color.RaiseEffect(spilled.GetColor(_prototypeManager), targets,
+ Filter.Pvs(entity, entityManager: EntityManager));
- return TrySpillAt(coordinates, solution, out puddleUid, sound);
+ return TrySpillAt(coordinates, spilled, out puddleUid, sound);
}
///
diff --git a/Content.Shared/Fluids/SharedPuddleSystem.cs b/Content.Shared/Fluids/SharedPuddleSystem.cs
index e81d1c9d114..8f87734717d 100644
--- a/Content.Shared/Fluids/SharedPuddleSystem.cs
+++ b/Content.Shared/Fluids/SharedPuddleSystem.cs
@@ -354,6 +354,15 @@ public abstract partial class SharedPuddleSystem : EntitySystem
}
#region Spill
+
+ ///
+ public abstract bool TrySplashSpillAt(Entity entity,
+ EntityCoordinates coordinates,
+ out EntityUid puddleUid,
+ out Solution spilled,
+ bool sound = true,
+ EntityUid? user = null);
+
// These methods are in Shared to make it easier to interact with PuddleSystem in Shared code.
// Note that they always fail when run on the client, not creating a puddle and returning false.
// Adding proper prediction to this system would require spawning temporary puddle entities on the
@@ -367,9 +376,9 @@ public abstract partial class SharedPuddleSystem : EntitySystem
///
/// On the client, this will always set to and return false.
///
- public abstract bool TrySplashSpillAt(EntityUid uid,
+ public abstract bool TrySplashSpillAt(EntityUid entity,
EntityCoordinates coordinates,
- Solution solution,
+ Solution spilled,
out EntityUid puddleUid,
bool sound = true,
EntityUid? user = null);
diff --git a/Content.Shared/Nutrition/EntitySystems/PressurizedSolutionSystem.cs b/Content.Shared/Nutrition/EntitySystems/PressurizedSolutionSystem.cs
index 82d90f4c928..9a0e3e79fa6 100644
--- a/Content.Shared/Nutrition/EntitySystems/PressurizedSolutionSystem.cs
+++ b/Content.Shared/Nutrition/EntitySystems/PressurizedSolutionSystem.cs
@@ -179,8 +179,8 @@ public sealed partial class PressurizedSolutionSystem : EntitySystem
var solution = _solutionContainer.SplitSolution(soln.Value, interactions.Volume);
// Spray the solution onto the ground and anyone nearby
- if (TryComp(entity, out TransformComponent? transform))
- _puddle.TrySplashSpillAt(entity, transform.Coordinates, solution, out _, sound: false);
+ var coordinates = Transform(entity).Coordinates;
+ _puddle.TrySplashSpillAt(entity.Owner, coordinates, out _, out _, sound: false);
var drinkName = Identity.Entity(entity, EntityManager);