diff --git a/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs index ff050ce2cda..d45fe707ab2 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs @@ -1,42 +1,60 @@ -using Content.Shared.Chemistry.EntitySystems; using Content.Server.Fluids.EntitySystems; +using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Fluids.Components; 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 - { - [DataField] - public string? Solution; + /// + /// Optional fallback solution name if SpillableComponent is not present. + /// + [DataField] + public string? Solution; - /// - /// 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(); + /// + /// 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) + { + var solutionContainerSystem = system.EntityManager.System(); + var spillableSystem = system.EntityManager.System(); + var coordinates = system.EntityManager.GetComponent(owner).Coordinates; - var coordinates = system.EntityManager.GetComponent(owner).Coordinates; + Solution targetSolution; - 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); - } + // First try to get solution from SpillableComponent + if (system.EntityManager.TryGetComponent(owner, out SpillableComponent? spillableComponent) && + solutionContainerSystem.TryGetSolution(owner, spillableComponent.SolutionName, out var solution, out var compSolution)) + { + // If entity is drainable, drain the solution. Otherwise just split it. + // Both methods ensure the solution is properly removed. + targetSolution = system.EntityManager.HasComponent(owner) + ? solutionContainerSystem.Drain((owner, system.EntityManager.GetComponent(owner)), solution.Value, compSolution.Volume) + : compSolution.SplitSolution(compSolution.Volume); } + // Fallback to solution specified in behavior data + else if (Solution != null && + solutionContainerSystem.TryGetSolution(owner, Solution, out var solutionEnt, out var behaviorSolution)) + { + targetSolution = system.EntityManager.HasComponent(owner) + ? solutionContainerSystem.Drain((owner, system.EntityManager.GetComponent(owner)), solutionEnt.Value, behaviorSolution.Volume) + : behaviorSolution.SplitSolution(behaviorSolution.Volume); + } + else + return; + + // Spill the solution that was drained/split + spillableSystem.TrySplashSpillAt(owner, coordinates, targetSolution, out _, false, cause); } }