using Content.Server.Body.Systems; using Content.Shared.Administration.Logs; using Content.Shared.Body.Components; using Content.Shared.Chemistry; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Database; using Content.Shared.FixedPoint; using Content.Shared.Fluids.Components; using Content.Shared.Rootable; using Robust.Shared.Timing; namespace Content.Server.Rootable; // TODO: Move all of this to shared /// /// Adds an action to toggle rooting to the ground, primarily for the Diona species. /// public sealed class RootableSystem : SharedRootableSystem { [Dependency] private readonly ISharedAdminLogManager _logger = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!; [Dependency] private readonly ReactiveSystem _reactive = default!; [Dependency] private readonly BloodstreamSystem _blood = default!; public override void Update(float frameTime) { base.Update(frameTime); var query = EntityQueryEnumerator(); var curTime = _timing.CurTime; while (query.MoveNext(out var uid, out var rooted, out var bloodstream)) { if (!rooted.Rooted || rooted.PuddleEntity == null || curTime < rooted.NextUpdate || !PuddleQuery.TryComp(rooted.PuddleEntity, out var puddleComp)) continue; rooted.NextUpdate += rooted.TransferFrequency; PuddleReact((uid, rooted, bloodstream), (rooted.PuddleEntity.Value, puddleComp!)); } } /// /// Determines if the puddle is set up properly and if so, moves on to reacting. /// private void PuddleReact(Entity entity, Entity puddleEntity) { if (!_solutionContainer.ResolveSolution(puddleEntity.Owner, puddleEntity.Comp.SolutionName, ref puddleEntity.Comp.Solution, out var solution) || solution.Contents.Count == 0) { return; } ReactWithEntity(entity, puddleEntity, solution); } /// /// Attempt to transfer an amount of the solution to the entity's bloodstream. /// private void ReactWithEntity(Entity entity, Entity puddleEntity, Solution solution) { if (!_solutionContainer.ResolveSolution(entity.Owner, entity.Comp2.ChemicalSolutionName, ref entity.Comp2.ChemicalSolution, out var chemSolution) || chemSolution.AvailableVolume <= 0) return; var availableTransfer = FixedPoint2.Min(solution.Volume, entity.Comp1.TransferRate); var transferAmount = FixedPoint2.Min(availableTransfer, chemSolution.AvailableVolume); var transferSolution = _solutionContainer.SplitSolution(puddleEntity.Comp.Solution!.Value, transferAmount); _reactive.DoEntityReaction(entity, transferSolution, ReactionMethod.Ingestion); if (_blood.TryAddToChemicals((entity, entity.Comp2), transferSolution)) { // Log solution addition by puddle _logger.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(entity):target} absorbed puddle {SharedSolutionContainerSystem.ToPrettyString(transferSolution)}"); } } }