/// <summary>
        ///     Raised directed at a victim when someone has force fed them a drink.
        /// </summary>
        private void OnDrink(EntityUid uid, SharedBodyComponent body, DrinkEvent args)
        {
            if (args.Drink.Deleted)
            {
                return;
            }

            args.Drink.CancelToken = null;
            var transferAmount = FixedPoint2.Min(args.Drink.TransferAmount, args.DrinkSolution.DrainAvailable);
            var drained        = _solutionContainerSystem.Drain(args.Drink.Owner, args.DrinkSolution, transferAmount);

            var forceDrink = uid != args.User;

            if (!_bodySystem.TryGetComponentsOnMechanisms <StomachComponent>(uid, out var stomachs, body))
            {
                _popupSystem.PopupEntity(
                    forceDrink ?
                    Loc.GetString("drink-component-try-use-drink-cannot-drink-other") :
                    Loc.GetString("drink-component-try-use-drink-had-enough"),
                    uid, Filter.Entities(args.User));

                if (EntityManager.HasComponent <RefillableSolutionComponent>(uid))
                {
                    _spillableSystem.SpillAt(args.User, drained, "PuddleSmear");
                    return;
                }

                _solutionContainerSystem.Refill(uid, args.DrinkSolution, drained);
                return;
            }

            var firstStomach = stomachs.FirstOrNull(
                stomach => _stomachSystem.CanTransferSolution((stomach.Comp).Owner, drained));

            // All stomach are full or can't handle whatever solution we have.
            if (firstStomach == null)
            {
                _popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-had-enough-other"),
                                         uid, Filter.Entities(args.User));

                _spillableSystem.SpillAt(uid, drained, "PuddleSmear");
                return;
            }

            if (forceDrink)
            {
                EntityManager.TryGetComponent(uid, out MetaDataComponent? targetMeta);
                var targetName = targetMeta?.EntityName ?? string.Empty;

                EntityManager.TryGetComponent(args.User, out MetaDataComponent? userMeta);
                var userName = userMeta?.EntityName ?? string.Empty;

                _popupSystem.PopupEntity(
                    Loc.GetString("drink-component-force-feed-success", ("user", userName)), uid, Filter.Entities(uid));

                _popupSystem.PopupEntity(
                    Loc.GetString("drink-component-force-feed-success-user", ("target", targetName)),
                    args.User, Filter.Entities(args.User));
            }
            else
            {
                _popupSystem.PopupEntity(
                    Loc.GetString("drink-component-try-use-drink-success-slurp"), args.User, Filter.Pvs(args.User));
            }

            SoundSystem.Play(Filter.Pvs(uid), args.Drink.UseSound.GetSound(), uid, AudioParams.Default.WithVolume(-2f));

            drained.DoEntityReaction(uid, ReactionMethod.Ingestion);
            _stomachSystem.TryTransferSolution(firstStomach.Value.Comp.Owner, drained, firstStomach.Value.Comp);
        }
    public PuddleComponent?SpillAt(TileRef tileRef, Solution solution, string prototype,
                                   bool overflow = true, bool sound = true, bool noTileReact = false, bool combine = true)
    {
        if (solution.TotalVolume <= 0)
        {
            return(null);
        }

        // If space return early, let that spill go out into the void
        if (tileRef.Tile.IsEmpty)
        {
            return(null);
        }

        var gridId = tileRef.GridIndex;

        if (!_mapManager.TryGetGrid(gridId, out var mapGrid))
        {
            return(null);                                                  // Let's not spill to invalid grids.
        }
        if (!noTileReact)
        {
            // First, do all tile reactions
            foreach (var(reagentId, quantity) in solution.Contents)
            {
                var proto = _prototypeManager.Index <ReagentPrototype>(reagentId);
                proto.ReactionTile(tileRef, quantity);
            }
        }

        // Tile reactions used up everything.
        if (solution.CurrentVolume == FixedPoint2.Zero)
        {
            return(null);
        }

        // Get normalized co-ordinate for spill location and spill it in the centre
        // TODO: Does SnapGrid or something else already do this?
        var spillGridCoords = mapGrid.GridTileToWorld(tileRef.GridIndices);

        var spillEntities = _entityLookup.GetEntitiesIntersecting(mapGrid.ParentMapId, spillGridCoords.Position).ToArray();

        foreach (var spillEntity in spillEntities)
        {
            if (_solutionContainerSystem.TryGetRefillableSolution(spillEntity, out var solutionContainerComponent))
            {
                _solutionContainerSystem.Refill(spillEntity, solutionContainerComponent,
                                                solution.SplitSolution(FixedPoint2.Min(
                                                                           solutionContainerComponent.AvailableVolume,
                                                                           solutionContainerComponent.MaxSpillRefill))
                                                );
            }
        }

        if (combine)
        {
            foreach (var spillEntity in spillEntities)
            {
                if (!EntityManager.TryGetComponent(spillEntity, out PuddleComponent? puddleComponent))
                {
                    continue;
                }

                if (!overflow && _puddleSystem.WouldOverflow(puddleComponent.Owner, solution, puddleComponent))
                {
                    return(null);
                }

                if (!_puddleSystem.TryAddSolution(puddleComponent.Owner, solution, sound))
                {
                    continue;
                }

                return(puddleComponent);
            }
        }

        var puddleEnt          = EntityManager.SpawnEntity(prototype, spillGridCoords);
        var newPuddleComponent = EntityManager.GetComponent <PuddleComponent>(puddleEnt);

        _puddleSystem.TryAddSolution(newPuddleComponent.Owner, solution, sound);

        return(newPuddleComponent);
    }
Beispiel #3
0
        /// <summary>
        ///     Attempt to drink some of a drink. Returns true if any interaction took place, including generation of
        ///     pop-up messages.
        /// </summary>
        private bool TryUseDrink(EntityUid uid, EntityUid userUid, DrinkComponent?drink = null)
        {
            if (!Resolve(uid, ref drink))
            {
                return(false);
            }

            // if currently being used to force-feed, cancel that action.
            if (drink.CancelToken != null)
            {
                drink.CancelToken.Cancel();
                drink.CancelToken = null;
                return(true);
            }

            if (!drink.Opened)
            {
                _popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-not-open",
                                                       ("owner", Name: EntityManager.GetComponent <MetaDataComponent>(drink.Owner).EntityName)), uid, Filter.Entities(userUid));
                return(true);
            }

            if (!EntityManager.TryGetComponent(userUid, out SharedBodyComponent? body))
            {
                return(false);
            }

            if (!_solutionContainerSystem.TryGetDrainableSolution((drink).Owner, out var drinkSolution) ||
                drinkSolution.DrainAvailable <= 0)
            {
                _popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-is-empty",
                                                       ("entity", Name: EntityManager.GetComponent <MetaDataComponent>(drink.Owner).EntityName)), uid, Filter.Entities(userUid));
                return(true);
            }

            if (!_bodySystem.TryGetComponentsOnMechanisms <StomachComponent>(userUid, out var stomachs, body))
            {
                _popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-cannot-drink"),
                                         userUid, Filter.Entities(userUid));
                return(true);
            }

            if (_foodSystem.IsMouthBlocked(userUid, userUid))
            {
                return(true);
            }

            var transferAmount = FixedPoint2.Min(drink.TransferAmount, drinkSolution.DrainAvailable);
            var drain          = _solutionContainerSystem.Drain(uid, drinkSolution, transferAmount);
            var firstStomach   = stomachs.FirstOrNull(
                stomach => _stomachSystem.CanTransferSolution((stomach.Comp).Owner, drain));

            // All stomach are full or can't handle whatever solution we have.
            if (firstStomach == null)
            {
                _popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-had-enough"),
                                         userUid, Filter.Entities(userUid));

                if (EntityManager.HasComponent <RefillableSolutionComponent>(uid))
                {
                    _spillableSystem.SpillAt(userUid, drain, "PuddleSmear");
                    return(true);
                }

                _solutionContainerSystem.Refill(uid, drinkSolution, drain);
                return(true);
            }

            SoundSystem.Play(Filter.Pvs(userUid), drink.UseSound.GetSound(), userUid,
                             AudioParams.Default.WithVolume(-2f));

            _popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-success-slurp"), userUid,
                                     Filter.Pvs(userUid));

            drain.DoEntityReaction(userUid, ReactionMethod.Ingestion);
            _stomachSystem.TryTransferSolution((firstStomach.Value.Comp).Owner, drain, firstStomach.Value.Comp);

            return(true);
        }