protected override void Activate(IEntity user, SolutionContainerComponent component)
            {
                if (!user.TryGetComponent <HandsComponent>(out var hands) || hands.GetActiveHand == null)
                {
                    return;
                }

                if (!hands.GetActiveHand.Owner.TryGetComponent <SolutionContainerComponent>(out var handSolutionComp) ||
                    !handSolutionComp.CanAddSolutions ||
                    !component.CanRemoveSolutions)
                {
                    return;
                }

                var transferQuantity = ReagentUnit.Min(handSolutionComp.MaxVolume - handSolutionComp.CurrentVolume, component.CurrentVolume, ReagentUnit.New(10));

                if (transferQuantity <= 0)
                {
                    return;
                }

                var transferSolution = component.SplitSolution(transferQuantity);

                handSolutionComp.TryAddSolution(transferSolution);
            }
        /// <returns>The actual amount transferred.</returns>
        private static ReagentUnit DoTransfer(IEntity user,
                                              IEntity sourceEntity,
                                              Solution source,
                                              IEntity targetEntity,
                                              Solution target,
                                              ReagentUnit amount)
        {
            if (source.DrainAvailable == 0)
            {
                sourceEntity.PopupMessage(user,
                                          Loc.GetString("comp-solution-transfer-is-empty", ("target", sourceEntity)));
                return(ReagentUnit.Zero);
            }

            if (target.AvailableVolume == 0)
            {
                targetEntity.PopupMessage(user,
                                          Loc.GetString("comp-solution-transfer-is-full", ("target", targetEntity)));
                return(ReagentUnit.Zero);
            }

            var actualAmount =
                ReagentUnit.Min(amount, ReagentUnit.Min(source.DrainAvailable, target.AvailableVolume));

            var solution = EntitySystem.Get <SolutionContainerSystem>().Drain(sourceEntity.Uid, source, actualAmount);

            EntitySystem.Get <SolutionContainerSystem>().Refill(targetEntity.Uid, target, solution);

            return(actualAmount);
        }
예제 #3
0
        protected override void ReactWithEntity(IEntity entity, double solutionFraction)
        {
            if (SolutionContainerComponent == null)
            {
                return;
            }

            if (!entity.TryGetComponent(out BloodstreamComponent? bloodstream))
            {
                return;
            }

            if (entity.TryGetComponent(out InternalsComponent? internals) &&
                internals.AreInternalsWorking())
            {
                return;
            }

            var cloneSolution    = SolutionContainerComponent.Solution.Clone();
            var transferAmount   = ReagentUnit.Min(cloneSolution.TotalVolume * solutionFraction, bloodstream.EmptyVolume);
            var transferSolution = cloneSolution.SplitSolution(transferAmount);

            foreach (var reagentQuantity in transferSolution.Contents.ToArray())
            {
                if (reagentQuantity.Quantity == ReagentUnit.Zero)
                {
                    continue;
                }
                var reagent = PrototypeManager.Index <ReagentPrototype>(reagentQuantity.ReagentId);
                transferSolution.RemoveReagent(reagentQuantity.ReagentId, reagent.ReactionEntity(entity, ReactionMethod.Ingestion, reagentQuantity.Quantity));
            }

            bloodstream.TryTransferSolution(transferSolution);
        }
        async Task <bool> IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
        {
            var solutionContainerSystem = EntitySystem.Get <SolutionContainerSystem>();

            if (eventArgs.Target == null || !eventArgs.CanReach)
            {
                return(false);
            }

            var targetEntity = eventArgs.Target;

            if (eventArgs.Target.HasComponent <ReagentTankComponent>() &&
                solutionContainerSystem.TryGetDrainableSolution(targetEntity.Uid, out var targetSolution) &&
                solutionContainerSystem.TryGetDrainableSolution(Owner.Uid, out var container))
            {
                var transfer = ReagentUnit.Min(container.AvailableVolume, targetSolution.DrainAvailable);
                if (transfer > 0)
                {
                    var drained = solutionContainerSystem.Drain(targetEntity.Uid, targetSolution, transfer);
                    solutionContainerSystem.TryAddSolution(Owner.Uid, container, drained);

                    SoundSystem.Play(Filter.Pvs(Owner), _refillSound.GetSound(), Owner);
                    eventArgs.Target.PopupMessage(eventArgs.User,
                                                  Loc.GetString("fire-extinguisher-component-after-interact-refilled-message", ("owner", Owner)));
                }

                return(true);
            }

            return(false);
        }
예제 #5
0
        public override void Activate(IEntity user, IEntity target)
        {
            if (!GetHeldSolution(user, out _, out var handSolutionComp))
            {
                return;
            }

            if (!handSolutionComp.CanDrain ||
                !target.TryGetComponent(out ISolutionInteractionsComponent? targetComp) ||
                !targetComp.CanRefill)
            {
                return;
            }

            var transferQuantity = ReagentUnit.Min(
                targetComp.RefillSpaceAvailable,
                handSolutionComp.DrainAvailable,
                ReagentUnit.New(10));

            if (transferQuantity <= 0)
            {
                return;
            }

            var transferSolution = handSolutionComp.Drain(transferQuantity);

            targetComp.Refill(transferSolution);
        }
예제 #6
0
        void UseFood(IEntity user)
        {
            if (user == null)
            {
                return;
            }

            if (UsesLeft() == 0)
            {
                user.PopupMessage(user, _localizationManager.GetString("Empty"));
            }
            else
            {
                // TODO: Add putting food back in boxes here?
                if (user.TryGetComponent(out StomachComponent stomachComponent))
                {
                    var transferAmount = ReagentUnit.Min(_transferAmount, _contents.CurrentVolume);
                    var split          = _contents.SplitSolution(transferAmount);
                    if (stomachComponent.TryTransferSolution(split))
                    {
                        if (_useSound != null)
                        {
                            Owner.GetComponent <SoundComponent>()?.Play(_useSound);
                            user.PopupMessage(user, _localizationManager.GetString("Nom"));
                        }
                    }
                    else
                    {
                        // Add it back in
                        _contents.TryAddSolution(split);
                        user.PopupMessage(user, _localizationManager.GetString("Can't eat"));
                    }
                }
            }

            if (UsesLeft() > 0)
            {
                return;
            }

            var position = Owner.Transform.GridPosition;

            Owner.Delete();

            if (_finishPrototype != null)
            {
                var finisher = Owner.EntityManager.SpawnEntity(_finishPrototype, position);
                if (user.TryGetComponent(out HandsComponent handsComponent) && finisher.TryGetComponent(out ItemComponent itemComponent))
                {
                    if (handsComponent.CanPutInHand(itemComponent))
                    {
                        handsComponent.PutInHand(itemComponent);
                        return;
                    }
                }

                finisher.Transform.GridPosition = user.Transform.GridPosition;
                return;
            }
        }
예제 #7
0
        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);
        }
        async Task <bool> IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
        {
            if (eventArgs.Target == null || !eventArgs.CanReach)
            {
                return(false);
            }

            if (eventArgs.Target.TryGetComponent(out ReagentTankComponent? tank) &&
                eventArgs.Target.TryGetComponent(out ISolutionInteractionsComponent? targetSolution) &&
                targetSolution.CanDrain &&
                Owner.TryGetComponent(out SolutionContainerComponent? container))
            {
                var trans = ReagentUnit.Min(container.EmptyVolume, targetSolution.DrainAvailable);
                if (trans > 0)
                {
                    var drained = targetSolution.Drain(trans);
                    container.TryAddSolution(drained);

                    SoundSystem.Play(Filter.Pvs(Owner), _refillSound.GetSound(), Owner);
                    eventArgs.Target.PopupMessage(eventArgs.User, Loc.GetString("fire-extinguisher-component-after-interact-refilled-message", ("owner", Owner)));
                }

                return(true);
            }

            return(false);
        }
        private void TryInjectIntoBloodstream(BloodstreamComponent targetBloodstream, IEntity user)
        {
            if (!Owner.TryGetComponent(out SolutionContainerComponent? solution) || solution.CurrentVolume == 0)
            {
                return;
            }

            // Get transfer amount. May be smaller than _transferAmount if not enough room
            var realTransferAmount = ReagentUnit.Min(_transferAmount, targetBloodstream.EmptyVolume);

            if (realTransferAmount <= 0)
            {
                Owner.PopupMessage(user, Loc.GetString("You aren't able to inject {0:theName}!", targetBloodstream.Owner));
                return;
            }

            // Move units from attackSolution to targetSolution
            var removedSolution = solution.SplitSolution(realTransferAmount);

            if (!targetBloodstream.TryTransferSolution(removedSolution))
            {
                return;
            }

            Owner.PopupMessage(user, Loc.GetString("You inject {0}u into {1:theName}!", removedSolution.TotalVolume, targetBloodstream.Owner));
            Dirty();
        }
        protected override void ReactWithEntity(IEntity entity, double solutionFraction)
        {
            if (!EntitySystem.Get <SolutionContainerSystem>().TryGetSolution(Owner, SolutionName, out var solution))
            {
                return;
            }

            if (!entity.TryGetComponent(out BloodstreamComponent? bloodstream))
            {
                return;
            }

            if (entity.TryGetComponent(out InternalsComponent? internals) &&
                internals.AreInternalsWorking())
            {
                return;
            }

            var chemistry        = EntitySystem.Get <ChemistrySystem>();
            var cloneSolution    = solution.Clone();
            var transferAmount   = ReagentUnit.Min(cloneSolution.TotalVolume * solutionFraction, bloodstream.EmptyVolume);
            var transferSolution = cloneSolution.SplitSolution(transferAmount);

            foreach (var reagentQuantity in transferSolution.Contents.ToArray())
            {
                if (reagentQuantity.Quantity == ReagentUnit.Zero)
                {
                    continue;
                }
                chemistry.ReactionEntity(entity, ReactionMethod.Ingestion, reagentQuantity.ReagentId, reagentQuantity.Quantity, transferSolution);
            }

            bloodstream.TryTransferSolution(transferSolution);
        }
예제 #11
0
        async Task <bool> IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
        {
            if (eventArgs.Target == null || !eventArgs.CanReach)
            {
                return(false);
            }

            if (eventArgs.Target.TryGetComponent(out ReagentTankComponent? tank) &&
                eventArgs.Target.TryGetComponent(out ISolutionInteractionsComponent? targetSolution) &&
                targetSolution.CanDrain &&
                Owner.TryGetComponent(out SolutionContainerComponent? container))
            {
                var trans = ReagentUnit.Min(container.EmptyVolume, targetSolution.DrainAvailable);
                if (trans > 0)
                {
                    var drained = targetSolution.Drain(trans);
                    container.TryAddSolution(drained);

                    EntitySystem.Get <AudioSystem>().PlayFromEntity("/Audio/Effects/refill.ogg", Owner);
                    eventArgs.Target.PopupMessage(eventArgs.User, Loc.GetString("{0:TheName} is now refilled", Owner));
                }

                return(true);
            }

            return(false);
        }
        private void TryDraw(SolutionContainerComponent targetSolution, IEntity user)
        {
            if (!Owner.TryGetComponent(out SolutionContainerComponent? solution) || solution.EmptyVolume == 0)
            {
                return;
            }

            // Get transfer amount. May be smaller than _transferAmount if not enough room
            var realTransferAmount = ReagentUnit.Min(_transferAmount, targetSolution.CurrentVolume);

            if (realTransferAmount <= 0)
            {
                Owner.PopupMessage(user, Loc.GetString("{0:theName} is empty!", targetSolution.Owner));
                return;
            }

            // Move units from attackSolution to targetSolution
            var removedSolution = targetSolution.SplitSolution(realTransferAmount);

            if (!solution.TryAddSolution(removedSolution))
            {
                return;
            }

            Owner.PopupMessage(user, Loc.GetString("Drew {0}u from {1:theName}", removedSolution.TotalVolume, targetSolution.Owner));
            Dirty();
        }
예제 #13
0
        private bool TryUseDrink(IEntity target, bool forced = false)
        {
            if (target == null || !_contents.CanRemoveSolutions)
            {
                return(false);
            }

            if (!Opened)
            {
                target.PopupMessage(Loc.GetString("Open {0:theName} first!", Owner));
                return(false);
            }

            if (_contents.CurrentVolume.Float() <= 0)
            {
                if (!forced)
                {
                    target.PopupMessage(Loc.GetString("{0:theName} is empty!", Owner));
                }

                return(false);
            }

            if (!target.TryGetComponent(out IBody body) ||
                !body.TryGetMechanismBehaviors <StomachBehavior>(out var stomachs))
            {
                return(false);
            }

            var transferAmount = ReagentUnit.Min(TransferAmount, _contents.CurrentVolume);
            var split          = _contents.SplitSolution(transferAmount);
            var firstStomach   = stomachs.FirstOrDefault(stomach => stomach.CanTransferSolution(split));


            // All stomach are full or can't handle whatever solution we have.
            if (firstStomach == null)
            {
                _contents.TryAddSolution(split);
                target.PopupMessage(Loc.GetString("You've had enough {0:theName}!", Owner));
                return(false);
            }

            if (_useSound != null)
            {
                EntitySystem.Get <AudioSystem>().PlayFromEntity(_useSound, target, AudioParams.Default.WithVolume(-2f));
            }

            target.PopupMessage(Loc.GetString("Slurp"));
            UpdateAppearance();

            // TODO: Account for partial transfer.

            split.DoEntityReaction(target, ReactionMethod.Ingestion);

            firstStomach.TryTransferSolution(split);

            return(true);
        }
        private void TransferReagent(string id, ReagentUnit amount, bool isBuffer)
        {
            if (!HasBeaker && BufferModeTransfer)
            {
                return;
            }
            var beaker         = _beakerContainer.ContainedEntity;
            var beakerSolution = beaker.GetComponent <SolutionComponent>();

            if (isBuffer)
            {
                foreach (var reagent in BufferSolution.Solution.Contents)
                {
                    if (reagent.ReagentId == id)
                    {
                        ReagentUnit actualAmount;
                        if (amount == ReagentUnit.New(-1))
                        {
                            actualAmount = ReagentUnit.Min(reagent.Quantity, beakerSolution.EmptyVolume);
                        }
                        else
                        {
                            actualAmount = ReagentUnit.Min(reagent.Quantity, amount, beakerSolution.EmptyVolume);
                        }

                        BufferSolution.Solution.RemoveReagent(id, actualAmount);
                        if (BufferModeTransfer)
                        {
                            beakerSolution.Solution.AddReagent(id, actualAmount);
                        }
                        break;
                    }
                }
            }
            else
            {
                foreach (var reagent in beakerSolution.Solution.Contents)
                {
                    if (reagent.ReagentId == id)
                    {
                        ReagentUnit actualAmount;
                        if (amount == ReagentUnit.New(-1))
                        {
                            actualAmount = ReagentUnit.Min(reagent.Quantity, BufferSolution.EmptyVolume);
                        }
                        else
                        {
                            actualAmount = ReagentUnit.Min(reagent.Quantity, amount, BufferSolution.EmptyVolume);
                        }
                        beakerSolution.TryRemoveReagent(id, actualAmount);
                        BufferSolution.Solution.AddReagent(id, actualAmount);
                        break;
                    }
                }
            }

            UpdateUserInterface();
        }
예제 #15
0
        public bool InteractUsing(InteractUsingEventArgs eventArgs)
        {
            if (!_powered)
            {
                _notifyManager.PopupMessage(Owner.Transform.GridPosition, eventArgs.User,
                                            Loc.GetString("It has no power!"));
                return(false);
            }

            var itemEntity = eventArgs.User.GetComponent <HandsComponent>().GetActiveHand?.Owner;

            if (itemEntity == null)
            {
                eventArgs.User.PopupMessage(eventArgs.User, Loc.GetString("You have no active hand!"));
                return(false);
            }

            if (itemEntity.TryGetComponent <PourableComponent>(out var attackPourable))
            {
                if (!itemEntity.TryGetComponent <SolutionComponent>(out var attackSolution) ||
                    !attackSolution.CanPourOut)
                {
                    return(false);
                }

                //Get transfer amount. May be smaller than _transferAmount if not enough room
                var realTransferAmount = ReagentUnit.Min(attackPourable.TransferAmount, _solution.EmptyVolume);
                if (realTransferAmount <= 0) //Special message if container is full
                {
                    _notifyManager.PopupMessage(Owner.Transform.GridPosition, eventArgs.User,
                                                Loc.GetString("Container is full"));
                    return(false);
                }

                //Move units from attackSolution to targetSolution
                var removedSolution = attackSolution.SplitSolution(realTransferAmount);
                if (!_solution.TryAddSolution(removedSolution))
                {
                    return(false);
                }

                _notifyManager.PopupMessage(Owner.Transform.GridPosition, eventArgs.User,
                                            Loc.GetString("Transferred {0}u", removedSolution.TotalVolume));
                return(true);
            }

            if (!itemEntity.TryGetComponent(typeof(ItemComponent), out var food))
            {
                _notifyManager.PopupMessage(Owner, eventArgs.User, "That won't work!");
                return(false);
            }

            var ent = food.Owner; //Get the entity of the ItemComponent.

            _storage.Insert(ent);
            _uiDirty = true;
            return(true);
        }
예제 #16
0
        public bool TryDoInject(IEntity?target, IEntity user)
        {
            if (target == null || !EligibleEntity(target))
            {
                return(false);
            }

            string?msgFormat = null;

            if (target == user)
            {
                msgFormat = "hypospray-component-inject-self-message";
            }
            else if (EligibleEntity(user) && ClumsyComponent.TryRollClumsy(user, ClumsyFailChance))
            {
                msgFormat = "hypospray-component-inject-self-clumsy-message";
                target    = user;
            }

            if (_solution == null || _solution.CurrentVolume == 0)
            {
                user.PopupMessageCursor(Loc.GetString("hypospray-component-empty-message"));
                return(true);
            }

            user.PopupMessage(Loc.GetString(msgFormat ?? "hypospray-component-inject-other-message", ("other", target)));
            if (target != user)
            {
                target.PopupMessage(Loc.GetString("hypospray-component-feel-prick-message"));
                var meleeSys = EntitySystem.Get <MeleeWeaponSystem>();
                var angle    = Angle.FromWorldVec(target.Transform.WorldPosition - user.Transform.WorldPosition);
                meleeSys.SendLunge(angle, user);
            }

            SoundSystem.Play(Filter.Pvs(user), _injectSound.GetSound(), user);

            var targetSolution = target.GetComponent <SolutionContainerComponent>();

            // Get transfer amount. May be smaller than _transferAmount if not enough room
            var realTransferAmount = ReagentUnit.Min(TransferAmount, targetSolution.EmptyVolume);

            if (realTransferAmount <= 0)
            {
                user.PopupMessage(user, Loc.GetString("hypospray-component-transfer-already-full-message ", ("owner", targetSolution.Owner)));
                return(true);
            }

            // Move units from attackSolution to targetSolution
            var removedSolution = _solution.SplitSolution(realTransferAmount);

            if (!targetSolution.CanAddSolution(removedSolution))
            {
                return(true);
            }

            removedSolution.DoEntityReaction(target, ReactionMethod.Injection);

            targetSolution.TryAddSolution(removedSolution);
예제 #17
0
        private bool TryDoInject(IEntity?target, IEntity user)
        {
            if (target == null || !EligibleEntity(target))
            {
                return(false);
            }

            var msgFormat = "You inject {0:TheName}.";

            if (target == user)
            {
                msgFormat = "You inject yourself.";
            }
            else if (EligibleEntity(user) && ClumsyComponent.TryRollClumsy(user, ClumsyFailChance))
            {
                msgFormat = "Oops! You injected yourself!";
                target    = user;
            }

            if (_solution == null || _solution.CurrentVolume == 0)
            {
                user.PopupMessageCursor(Loc.GetString("It's empty!"));
                return(true);
            }

            user.PopupMessage(Loc.GetString(msgFormat, target));
            if (target != user)
            {
                target.PopupMessage(Loc.GetString("You feel a tiny prick!"));
                var meleeSys = EntitySystem.Get <MeleeWeaponSystem>();
                var angle    = new Angle(target.Transform.WorldPosition - user.Transform.WorldPosition);
                meleeSys.SendLunge(angle, user);
            }

            EntitySystem.Get <AudioSystem>().PlayFromEntity("/Audio/Items/hypospray.ogg", user);

            var targetSolution = target.GetComponent <SolutionContainerComponent>();

            // Get transfer amount. May be smaller than _transferAmount if not enough room
            var realTransferAmount = ReagentUnit.Min(TransferAmount, targetSolution.EmptyVolume);

            if (realTransferAmount <= 0)
            {
                user.PopupMessage(user, Loc.GetString("{0:TheName} is already full!", targetSolution.Owner));
                return(true);
            }

            // Move units from attackSolution to targetSolution
            var removedSolution = _solution.SplitSolution(realTransferAmount);

            if (!targetSolution.CanAddSolution(removedSolution))
            {
                return(true);
            }

            removedSolution.DoEntityReaction(target, ReactionMethod.Injection);

            targetSolution.TryAddSolution(removedSolution);
예제 #18
0
        public override bool TryUseFood(IEntity user, IEntity target, UtensilComponent utensilUsed = null)
        {
            if (user == null)
            {
                return(false);
            }

            var trueTarget = target ?? user;

            if (!trueTarget.TryGetComponent(out IBody body) ||
                !body.TryGetMechanismBehaviors <StomachBehavior>(out var stomachs))
            {
                return(false);
            }

            if (!user.InRangeUnobstructed(trueTarget, popup: true))
            {
                return(false);
            }

            var transferAmount = ReagentUnit.Min(_transferAmount, _contents.CurrentVolume);
            var split          = _contents.SplitSolution(transferAmount);

            var firstStomach = stomachs.FirstOrDefault(stomach => stomach.CanTransferSolution(split));

            if (firstStomach == null)
            {
                _contents.TryAddSolution(split);
                trueTarget.PopupMessage(user, Loc.GetString("You can't eat any more!"));
                return(false);
            }

            // TODO: Account for partial transfer.

            foreach (var(reagentId, quantity) in split.Contents)
            {
                if (!_prototypeManager.TryIndex(reagentId, out ReagentPrototype reagent))
                {
                    continue;
                }
                split.RemoveReagent(reagentId, reagent.ReactionEntity(trueTarget, ReactionMethod.Ingestion, quantity));
            }

            firstStomach.TryTransferSolution(split);

            if (_useSound != null)
            {
                _entitySystem.GetEntitySystem <AudioSystem>()
                .PlayFromEntity(_useSound, trueTarget, AudioParams.Default.WithVolume(-1f));
            }

            trueTarget.PopupMessage(user, Loc.GetString("You swallow the pill."));

            Owner.Delete();
            return(true);
        }
예제 #19
0
        private bool TryUseFood(IEntity user, IEntity target)
        {
            if (user == null)
            {
                return(false);
            }

            if (UsesRemaining <= 0)
            {
                user.PopupMessage(user, Loc.GetString($"The {Owner.Name} is empty!"));
                return(false);
            }

            var trueTarget = target ?? user;

            if (trueTarget.TryGetComponent(out StomachComponent stomachComponent))
            {
                var transferAmount = ReagentUnit.Min(_transferAmount, _contents.CurrentVolume);
                var split          = _contents.SplitSolution(transferAmount);
                if (stomachComponent.TryTransferSolution(split))
                {
                    _entitySystem.GetEntitySystem <AudioSystem>()
                    .Play(_useSound, trueTarget, AudioParams.Default.WithVolume(-1f));
                    trueTarget.PopupMessage(user, Loc.GetString("Nom"));
                }
                else
                {
                    _contents.TryAddSolution(split);
                    trueTarget.PopupMessage(user, Loc.GetString("You can't eat any more!"));
                }
            }

            if (UsesRemaining > 0)
            {
                return(true);
            }

            //We're empty. Become trash.
            var position = Owner.Transform.GridPosition;

            Owner.Delete();
            var finisher = Owner.EntityManager.SpawnEntity(_trashPrototype, position);

            if (user.TryGetComponent(out HandsComponent handsComponent) && finisher.TryGetComponent(out ItemComponent itemComponent))
            {
                if (handsComponent.CanPutInHand(itemComponent))
                {
                    handsComponent.PutInHand(itemComponent);
                    return(true);
                }
            }
            finisher.Transform.GridPosition = user.Transform.GridPosition;
            return(true);
        }
        public bool InteractUsing(InteractUsingEventArgs eventArgs)
        {
            var itemEntity = eventArgs.User.GetComponent <HandsComponent>().GetActiveHand.Owner;

            if (itemEntity.TryGetComponent <PourableComponent>(out var attackPourable))
            {
                //Get target and check if it can be poured into
                if (!Owner.TryGetComponent <SolutionComponent>(out var mySolution) ||
                    !mySolution.CanPourIn)
                {
                    return(false);
                }

                if (!itemEntity.TryGetComponent <SolutionComponent>(out var attackSolution) ||
                    !attackSolution.CanPourOut)
                {
                    return(false);
                }

                //Get transfer amount. May be smaller than _transferAmount if not enough room
                var realTransferAmount = ReagentUnit.Min(attackPourable.TransferAmount, mySolution.EmptyVolume);
                if (realTransferAmount <= 0) //Special message if container is full
                {
                    _notifyManager.PopupMessage(Owner.Transform.GridPosition, eventArgs.User,
                                                Loc.GetString("Container is full"));
                    return(false);
                }

                //Move units from attackSolution to targetSolution
                var removedSolution = attackSolution.SplitSolution(realTransferAmount);
                if (!mySolution.TryAddSolution(removedSolution))
                {
                    return(false);
                }

                _notifyManager.PopupMessage(Owner.Transform.GridPosition, eventArgs.User,
                                            Loc.GetString("Transferred {0}u", removedSolution.TotalVolume));
                return(true);
            }

            if (!itemEntity.TryGetComponent(typeof(FoodComponent), out var food))
            {
                _notifyManager.PopupMessage(Owner, eventArgs.User, "That won't work!");
                return(false);
            }

            var ent = food.Owner; //Get the entity of the ItemComponent.

            _storage.Insert(ent);
            UpdateUserInterface();
            return(true);
        }
        /// <summary>
        /// Will overflow this entity to neighboring entities if required
        /// </summary>
        private void CheckOverflow(PuddleComponent puddleComponent)
        {
            if (puddleComponent.CurrentVolume <= puddleComponent.OverflowVolume
                || puddleComponent.Overflown)
                return;

            var nextPuddles = new List<PuddleComponent>() { puddleComponent };
            var overflownPuddles = new List<PuddleComponent>();

            while (puddleComponent.OverflowLeft > ReagentUnit.Zero && nextPuddles.Count > 0)
            {
                foreach (var next in nextPuddles.ToArray())
                {
                    nextPuddles.Remove(next);

                    next.Overflown = true;
                    overflownPuddles.Add(next);

                    var adjacentPuddles = GetAllAdjacentOverflow(next).ToArray();
                    if (puddleComponent.OverflowLeft <= ReagentUnit.Epsilon * adjacentPuddles.Length)
                    {
                        break;
                    }

                    if (adjacentPuddles.Length == 0)
                    {
                        continue;
                    }

                    var numberOfAdjacent = ReagentUnit.New(adjacentPuddles.Length);
                    var overflowSplit = puddleComponent.OverflowLeft / numberOfAdjacent;
                    foreach (var adjacent in adjacentPuddles)
                    {
                        var adjacentPuddle = adjacent();
                        var quantity = ReagentUnit.Min(overflowSplit, adjacentPuddle.OverflowVolume);
                        var puddleSolution = _solutionContainerSystem.EnsureSolution(puddleComponent.Owner.Uid,
                            puddleComponent.SolutionName);
                        var spillAmount = _solutionContainerSystem.SplitSolution(puddleComponent.Owner.Uid,
                            puddleSolution, quantity);

                        TryAddSolution(adjacentPuddle.Owner.Uid, spillAmount, false, false);
                        nextPuddles.Add(adjacentPuddle);
                    }
                }
            }

            foreach (var puddle in overflownPuddles)
            {
                puddle.Overflown = false;
            }
        }
        public void ReagentUnitMin()
        {
            var unorderedList = new[]
            {
                ReagentUnit.New(5),
                ReagentUnit.New(3),
                ReagentUnit.New(1),
                ReagentUnit.New(2),
                ReagentUnit.New(4),
            };
            var min = ReagentUnit.Min(unorderedList);

            Assert.That(min, Is.EqualTo(ReagentUnit.New(1)));
        }
        public void ReagentUnitMin()
        {
            var unorderedList = new[]
            {
                ReagentUnit.New(5),
                ReagentUnit.New(3),
                ReagentUnit.New(1),
                ReagentUnit.New(2),
                ReagentUnit.New(4),
            };
            var min = ReagentUnit.Min(unorderedList);

            Assert.AreEqual(ReagentUnit.New(1), min);
        }
예제 #24
0
        private void TryInjectIntoBloodstream(BloodstreamComponent targetBloodstream, IEntity user)
        {
            if (!Owner.TryGetComponent(out SolutionContainerComponent? solution) || solution.CurrentVolume == 0)
            {
                return;
            }

            // Get transfer amount. May be smaller than _transferAmount if not enough room
            var realTransferAmount = ReagentUnit.Min(_transferAmount, targetBloodstream.EmptyVolume);

            if (realTransferAmount <= 0)
            {
                Owner.PopupMessage(user, Loc.GetString("You aren't able to inject {0:theName}!", targetBloodstream.Owner));
                return;
            }

            // Move units from attackSolution to targetSolution
            var removedSolution = solution.SplitSolution(realTransferAmount);

            if (!solution.CanAddSolution(removedSolution))
            {
                return;
            }

            // TODO: Account for partial transfer.

            foreach (var(reagentId, quantity) in removedSolution.Contents)
            {
                if (!_prototypeManager.TryIndex(reagentId, out ReagentPrototype reagent))
                {
                    continue;
                }
                removedSolution.RemoveReagent(reagentId, reagent.ReactionEntity(solution.Owner, ReactionMethod.Injection, quantity));
            }

            solution.TryAddSolution(removedSolution);

            foreach (var(reagentId, quantity) in removedSolution.Contents)
            {
                if (!_prototypeManager.TryIndex(reagentId, out ReagentPrototype reagent))
                {
                    continue;
                }
                reagent.ReactionEntity(targetBloodstream.Owner, ReactionMethod.Injection, quantity);
            }

            Owner.PopupMessage(user, Loc.GetString("You inject {0}u into {1:theName}!", removedSolution.TotalVolume, targetBloodstream.Owner));
            Dirty();
        }
예제 #25
0
        private bool TryUseDrink(IEntity target, bool forced = false)
        {
            if (target == null || !_contents.CanRemoveSolutions)
            {
                return(false);
            }

            if (!Opened)
            {
                target.PopupMessage(Loc.GetString("Open {0:theName} first!", Owner));
                return(false);
            }

            if (_contents.CurrentVolume.Float() <= 0)
            {
                if (!forced)
                {
                    target.PopupMessage(Loc.GetString("{0:theName} is empty!", Owner));
                }

                return(false);
            }

            if (!target.TryGetComponent(out StomachComponent stomachComponent))
            {
                return(false);
            }

            var transferAmount = ReagentUnit.Min(TransferAmount, _contents.CurrentVolume);
            var split          = _contents.SplitSolution(transferAmount);

            if (stomachComponent.TryTransferSolution(split))
            {
                if (_useSound == null)
                {
                    return(false);
                }

                EntitySystem.Get <AudioSystem>().PlayFromEntity(_useSound, target, AudioParams.Default.WithVolume(-2f));
                target.PopupMessage(Loc.GetString("Slurp"));
                UpdateAppearance();
                return(true);
            }

            // Stomach was full or can't handle whatever solution we have.
            _contents.TryAddSolution(split);
            target.PopupMessage(Loc.GetString("You've had enough {0:theName}!", Owner));
            return(false);
        }
예제 #26
0
        public override bool TryUseFood(IEntity?user, IEntity?target, UtensilComponent?utensilUsed = null)
        {
            if (user == null)
            {
                return(false);
            }

            var trueTarget = target ?? user;

            if (!trueTarget.TryGetComponent(out IBody? body) ||
                !body.TryGetMechanismBehaviors <StomachBehavior>(out var stomachs))
            {
                return(false);
            }

            if (!user.InRangeUnobstructed(trueTarget, popup: true))
            {
                return(false);
            }

            var transferAmount = ReagentUnit.Min(TransferAmount, _contents.CurrentVolume);
            var split          = _contents.SplitSolution(transferAmount);

            var firstStomach = stomachs.FirstOrDefault(stomach => stomach.CanTransferSolution(split));

            if (firstStomach == null)
            {
                _contents.TryAddSolution(split);
                trueTarget.PopupMessage(user, Loc.GetString("You can't eat any more!"));
                return(false);
            }

            // TODO: Account for partial transfer.

            split.DoEntityReaction(trueTarget, ReactionMethod.Ingestion);

            firstStomach.TryTransferSolution(split);

            if (UseSound != null)
            {
                SoundSystem.Play(Filter.Pvs(trueTarget), UseSound, trueTarget, AudioParams.Default.WithVolume(-1f));
            }

            trueTarget.PopupMessage(user, Loc.GetString("You swallow the pill."));

            Owner.Delete();
            return(true);
        }
예제 #27
0
        public override void Update(float frameTime)
        {
            base.Update(frameTime);
            var queueDelete = new RemQueue <EvaporationComponent>();

            foreach (var evaporationComponent in EntityManager.EntityQuery <EvaporationComponent>())
            {
                var uid = evaporationComponent.Owner.Uid;
                evaporationComponent.Accumulator += frameTime;

                if (!_solutionContainerSystem.TryGetSolution(uid, evaporationComponent.SolutionName, out var solution))
                {
                    // If no solution, delete the entity
                    queueDelete.Add(evaporationComponent);
                    continue;
                }

                if (evaporationComponent.Accumulator < evaporationComponent.EvaporateTime)
                {
                    continue;
                }

                evaporationComponent.Accumulator -= evaporationComponent.EvaporateTime;


                _solutionContainerSystem.SplitSolution(uid, solution,
                                                       ReagentUnit.Min(ReagentUnit.New(1), solution.CurrentVolume));

                if (solution.CurrentVolume == 0)
                {
                    EntityManager.QueueDeleteEntity(uid);
                }
                else if (solution.CurrentVolume <= evaporationComponent.LowerLimit ||
                         solution.CurrentVolume >= evaporationComponent.UpperLimit)
                {
                    queueDelete.Add(evaporationComponent);
                }
            }

            foreach (var evaporationComponent in queueDelete)
            {
                EntityManager.RemoveComponent(evaporationComponent.Owner.Uid, evaporationComponent);
            }
        }
예제 #28
0
        public void TryAddSolution(Solution solution)
        {
            if (solution.TotalVolume == 0)
            {
                return;
            }

            if (SolutionContainerComponent == null)
            {
                return;
            }

            var addSolution =
                solution.SplitSolution(ReagentUnit.Min(solution.TotalVolume, SolutionContainerComponent.EmptyVolume));

            SolutionContainerComponent.TryAddSolution(addSolution);

            UpdateVisuals();
        }
        public void TryAddSolution(Solution solution)
        {
            if (solution.TotalVolume == 0)
            {
                return;
            }

            if (!EntitySystem.Get <SolutionContainerSystem>().TryGetSolution(Owner, SolutionName, out var solutionArea))
            {
                return;
            }

            var addSolution =
                solution.SplitSolution(ReagentUnit.Min(solution.TotalVolume, solutionArea.AvailableVolume));

            EntitySystem.Get <SolutionContainerSystem>().TryAddSolution(Owner.Uid, solutionArea, addSolution);

            UpdateVisuals();
        }
예제 #30
0
        protected override void ReactWithEntity(IEntity entity, double solutionFraction)
        {
            if (!EntitySystem.Get <SolutionContainerSystem>().TryGetSolution(Owner, SolutionName, out var solution))
            {
                return;
            }

            if (!entity.TryGetComponent(out BloodstreamComponent? bloodstream))
            {
                return;
            }

            // TODO: Add a permeability property to clothing
            // For now it just adds to protection for each clothing equipped
            var protection = 0f;

            if (entity.TryGetComponent(out InventoryComponent? inventory))
            {
                foreach (var slot in inventory.Slots)
                {
                    if (slot == EquipmentSlotDefines.Slots.BACKPACK ||
                        slot == EquipmentSlotDefines.Slots.POCKET1 ||
                        slot == EquipmentSlotDefines.Slots.POCKET2 ||
                        slot == EquipmentSlotDefines.Slots.IDCARD)
                    {
                        continue;
                    }

                    if (inventory.TryGetSlotItem(slot, out ItemComponent _))
                    {
                        protection += 0.025f;
                    }
                }
            }

            var cloneSolution  = solution.Clone();
            var transferAmount = ReagentUnit.Min(cloneSolution.TotalVolume * solutionFraction * (1 - protection),
                                                 bloodstream.EmptyVolume);
            var transferSolution = cloneSolution.SplitSolution(transferAmount);

            bloodstream.TryTransferSolution(transferSolution);
        }