#nullable enable using System.Threading.Tasks; using Content.Shared.Chemistry; using Content.Shared.GameObjects.Components.Chemistry; using Content.Shared.Interfaces; using Content.Shared.Interfaces.GameObjects.Components; using Robust.Shared.GameObjects; using Robust.Shared.Localization; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Chemistry { /// /// Gives click behavior for transferring to/from other reagent containers. /// [RegisterComponent] public sealed class SolutionTransferComponent : Component, IAfterInteract { // Behavior is as such: // If it's a reagent tank, TAKE reagent. // If it's anything else, GIVE reagent. // Of course, only if possible. public override string Name => "SolutionTransfer"; private ReagentUnit _transferAmount; private bool _canReceive; private bool _canSend; /// /// The amount of solution to be transferred from this solution when clicking on other solutions with it. /// [ViewVariables(VVAccess.ReadWrite)] public ReagentUnit TransferAmount { get => _transferAmount; set => _transferAmount = value; } /// /// Can this entity take reagent from reagent tanks? /// [ViewVariables(VVAccess.ReadWrite)] public bool CanReceive { get => _canReceive; set => _canReceive = value; } /// /// Can this entity give reagent to other reagent containers? /// [ViewVariables(VVAccess.ReadWrite)] public bool CanSend { get => _canSend; set => _canSend = value; } public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); serializer.DataField(ref _transferAmount, "transferAmount", ReagentUnit.New(5)); serializer.DataField(ref _canReceive, "canReceive", true); serializer.DataField(ref _canSend, "canSend", true); } async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { if (!eventArgs.CanReach || eventArgs.Target == null) return false; if (!Owner.TryGetComponent(out ISolutionInteractionsComponent? ownerSolution)) return false; var target = eventArgs.Target; if (!target.TryGetComponent(out ISolutionInteractionsComponent? targetSolution)) { return false; } if (CanReceive && target.TryGetComponent(out ReagentTankComponent? tank) && ownerSolution.CanRefill && targetSolution.CanDrain) { var transferred = DoTransfer(targetSolution, ownerSolution, tank.TransferAmount, eventArgs.User); if (transferred > 0) { var toTheBrim = ownerSolution.RefillSpaceAvailable == 0; var msg = toTheBrim ? "You fill {0:TheName} to the brim with {1}u from {2:theName}" : "You fill {0:TheName} with {1}u from {2:theName}"; target.PopupMessage(eventArgs.User, Loc.GetString(msg, Owner, transferred, target)); return true; } } if (CanSend && targetSolution.CanRefill && ownerSolution.CanDrain) { var transferred = DoTransfer(ownerSolution, targetSolution, TransferAmount, eventArgs.User); if (transferred > 0) { Owner.PopupMessage(eventArgs.User, Loc.GetString("You transfer {0}u to {1:theName}.", transferred, target)); return true; } } return true; } /// The actual amount transferred. private static ReagentUnit DoTransfer( ISolutionInteractionsComponent source, ISolutionInteractionsComponent target, ReagentUnit amount, IEntity user) { if (source.DrainAvailable == 0) { source.Owner.PopupMessage(user, Loc.GetString("{0:TheName} is empty!", source.Owner)); return ReagentUnit.Zero; } if (target.RefillSpaceAvailable == 0) { target.Owner.PopupMessage(user, Loc.GetString("{0:TheName} is full!", target.Owner)); return ReagentUnit.Zero; } var actualAmount = ReagentUnit.Min(amount, ReagentUnit.Min(source.DrainAvailable, target.RefillSpaceAvailable)); var solution = source.Drain(actualAmount); target.Refill(solution); return actualAmount; } } }