示例#1
0
    private void HandleChemicalPayloadTrigger(EntityUid uid, ChemicalPayloadComponent component, TriggerEvent args)
    {
        if (component.BeakerSlotA.Item is not EntityUid beakerA ||
            component.BeakerSlotB.Item is not EntityUid beakerB ||
            !TryComp(beakerA, out FitsInDispenserComponent? compA) ||
            !TryComp(beakerB, out FitsInDispenserComponent? compB) ||
            !_solutionSystem.TryGetSolution(beakerA, compA.Solution, out var solutionA) ||
            !_solutionSystem.TryGetSolution(beakerB, compB.Solution, out var solutionB) ||
            solutionA.TotalVolume == 0 ||
            solutionB.TotalVolume == 0)
        {
            return;
        }

        var solStringA = SolutionContainerSystem.ToPrettyString(solutionA);
        var solStringB = SolutionContainerSystem.ToPrettyString(solutionB);

        _logSystem.Add(LogType.ChemicalReaction,
                       $"Chemical bomb payload {ToPrettyString(uid):payload} at {Transform(uid).MapPosition:location} is combining two solutions: {solStringA:solutionA} and {solStringB:solutionB}");

        solutionA.MaxVolume += solutionB.MaxVolume;
        _solutionSystem.TryAddSolution(beakerA, solutionA, solutionB);
        solutionB.RemoveAllSolution();

        // The grenade might be a dud. Redistribute solution:
        var tmpSol = _solutionSystem.SplitSolution(beakerA, solutionA, solutionA.CurrentVolume * solutionB.MaxVolume / solutionA.MaxVolume);

        _solutionSystem.TryAddSolution(beakerB, solutionB, tmpSol);
        solutionA.MaxVolume -= solutionB.MaxVolume;
        _solutionSystem.UpdateChemicals(beakerA, solutionA, false);
    }
    private void SpillOnLand(EntityUid uid, SpillableComponent component, LandEvent args)
    {
        if (!_solutionContainerSystem.TryGetSolution(uid, component.SolutionName, out var solution))
        {
            return;
        }

        if (args.User != null)
        {
            _logSystem.Add(LogType.Landed,
                           $"{ToPrettyString(uid):entity} spilled a solution {SolutionContainerSystem.ToPrettyString(solution):solution} on landing");
        }

        var drainedSolution = _solutionContainerSystem.Drain(uid, solution, solution.DrainAvailable);

        SpillAt(drainedSolution, EntityManager.GetComponent <TransformComponent>(uid).Coordinates, "PuddleSmear");
    }
        private bool TryDrink(EntityUid user, EntityUid target, DrinkComponent drink)
        {
            // cannot stack do-afters
            if (drink.CancelToken != null)
            {
                drink.CancelToken.Cancel();
                drink.CancelToken = null;
                return(true);
            }

            if (!EntityManager.HasComponent <SharedBodyComponent>(target))
            {
                return(false);
            }

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

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

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

            if (!_interactionSystem.InRangeUnobstructed(user, drink.Owner, popup: true))
            {
                return(true);
            }

            var forceDrink = user != target;

            if (forceDrink)
            {
                EntityManager.TryGetComponent(user, out MetaDataComponent? meta);
                var userName = meta?.EntityName ?? string.Empty;

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

                // logging
                _logSystem.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(user):user} is forcing {ToPrettyString(target):target} to drink {ToPrettyString(drink.Owner):drink} {SolutionContainerSystem.ToPrettyString(drinkSolution)}");
            }

            drink.CancelToken = new CancellationTokenSource();
            _doAfterSystem.DoAfter(new DoAfterEventArgs(user, forceDrink ? drink.ForceFeedDelay : drink.Delay, drink.CancelToken.Token, target)
            {
                BreakOnUserMove         = true,
                BreakOnDamage           = true,
                BreakOnStun             = true,
                BreakOnTargetMove       = true,
                MovementThreshold       = 0.01f,
                TargetFinishedEvent     = new DrinkEvent(user, drink, drinkSolution),
                BroadcastCancelledEvent = new DrinkCancelledEvent(drink),
                NeedHand = true,
            });

            return(true);
        }
        public bool TryFeed(EntityUid user, EntityUid target, FoodComponent food)
        {
            // if currently being used to feed, cancel that action.
            if (food.CancelToken != null)
            {
                food.CancelToken.Cancel();
                food.CancelToken = null;
                return(true);
            }

            if (food.Owner == user ||                                                                                  //Suppresses self-eating
                EntityManager.TryGetComponent <MobStateComponent>(food.Owner, out var mobState) && mobState.IsAlive()) // Suppresses eating alive mobs
            {
                return(false);
            }

            // Target can't be fed
            if (!EntityManager.HasComponent <SharedBodyComponent>(target))
            {
                return(false);
            }

            if (!_solutionContainerSystem.TryGetSolution(food.Owner, food.SolutionName, out var foodSolution))
            {
                return(false);
            }

            if (food.UsesRemaining <= 0)
            {
                _popupSystem.PopupEntity(Loc.GetString("food-system-try-use-food-is-empty",
                                                       ("entity", food.Owner)), user, Filter.Entities(user));
                DeleteAndSpawnTrash(food, user);
                return(false);
            }

            if (IsMouthBlocked(target, user))
            {
                return(false);
            }

            if (!TryGetRequiredUtensils(user, food, out var utensils))
            {
                return(false);
            }

            if (!_interactionSystem.InRangeUnobstructed(user, food.Owner, popup: true))
            {
                return(true);
            }

            var forceFeed = user != target;

            food.CancelToken = new CancellationTokenSource();

            if (forceFeed)
            {
                EntityManager.TryGetComponent(user, out MetaDataComponent? meta);
                var userName = meta?.EntityName ?? string.Empty;

                _popupSystem.PopupEntity(Loc.GetString("food-system-force-feed", ("user", userName)),
                                         user, Filter.Entities(target));

                // logging
                _logSystem.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(user):user} is forcing {ToPrettyString(target):target} to eat {ToPrettyString(food.Owner):food} {SolutionContainerSystem.ToPrettyString(foodSolution)}");
            }

            var moveBreak = user != target;

            _doAfterSystem.DoAfter(new DoAfterEventArgs(user, forceFeed ? food.ForceFeedDelay : food.Delay, food.CancelToken.Token, target)
            {
                BreakOnUserMove         = moveBreak,
                BreakOnDamage           = true,
                BreakOnStun             = true,
                BreakOnTargetMove       = moveBreak,
                MovementThreshold       = 0.01f,
                TargetFinishedEvent     = new FeedEvent(user, food, foodSolution, utensils),
                BroadcastCancelledEvent = new ForceFeedCancelledEvent(food),
                NeedHand = true,
            });

            return(true);
        }
        /// <summary>
        ///     Force feeds someone remotely. Does not require utensils (well, not the normal type anyways).
        /// </summary>
        public void ProjectileForceFeed(EntityUid uid, EntityUid target, EntityUid?user, FoodComponent?food = null, BodyComponent?body = null)
        {
            // TODO: Combine with regular feeding because holy code duplication batman.
            if (!Resolve(uid, ref food, false) || !Resolve(target, ref body, false))
            {
                return;
            }

            if (IsMouthBlocked(target))
            {
                return;
            }

            if (!_solutionContainerSystem.TryGetSolution(uid, food.SolutionName, out var foodSolution))
            {
                return;
            }

            if (!_bodySystem.TryGetComponentsOnMechanisms <StomachComponent>(target, out var stomachs, body))
            {
                return;
            }

            if (food.UsesRemaining <= 0)
            {
                DeleteAndSpawnTrash(food);
            }

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

            if (firstStomach == null)
            {
                return;
            }

            // logging
            if (user == null)
            {
                _logSystem.Add(LogType.ForceFeed, $"{ToPrettyString(uid):food} {SolutionContainerSystem.ToPrettyString(foodSolution):solution} was thrown into the mouth of {ToPrettyString(target):target}");
            }
            else
            {
                _logSystem.Add(LogType.ForceFeed, $"{ToPrettyString(user.Value):user} threw {ToPrettyString(uid):food} {SolutionContainerSystem.ToPrettyString(foodSolution):solution} into the mouth of {ToPrettyString(target):target}");
            }

            var filter = user == null?Filter.Entities(target) : Filter.Entities(target, user.Value);

            _popupSystem.PopupEntity(Loc.GetString(food.EatMessage), target, filter);

            foodSolution.DoEntityReaction(uid, ReactionMethod.Ingestion);
            _stomachSystem.TryTransferSolution(((IComponent)firstStomach.Value.Comp).Owner, foodSolution, firstStomach.Value.Comp);
            SoundSystem.Play(Filter.Pvs(target), food.UseSound.GetSound(), target, AudioParams.Default.WithVolume(-1f));

            if (string.IsNullOrEmpty(food.TrashPrototype))
            {
                EntityManager.QueueDeleteEntity(food.Owner);
            }
            else
            {
                DeleteAndSpawnTrash(food);
            }
        }
    /// <summary>
    /// Send informative pop-up messages and wait for a do-after to complete.
    /// </summary>
    private void InjectDoAfter(InjectorComponent component, EntityUid user, EntityUid target)
    {
        // Create a pop-up for the user
        _popup.PopupEntity(Loc.GetString("injector-component-injecting-user"), target, Filter.Entities(user));

        if (!_solutions.TryGetSolution(component.Owner, InjectorComponent.SolutionName, out var solution))
        {
            return;
        }

        var actualDelay = MathF.Max(component.Delay, 1f);

        if (user != target)
        {
            // Create a pop-up for the target
            var userName = MetaData(user).EntityName;
            _popup.PopupEntity(Loc.GetString("injector-component-injecting-target",
                                             ("user", userName)), user, Filter.Entities(target));

            // Check if the target is incapacitated or in combat mode and modify time accordingly.
            if (TryComp <MobStateComponent>(target, out var mobState) && mobState.IsIncapacitated())
            {
                actualDelay /= 2;
            }
            else if (TryComp <CombatModeComponent>(target, out var combat) && combat.IsInCombatMode)
            {
                // Slightly increase the delay when the target is in combat mode. Helps prevents cheese injections in
                // combat with fast syringes & lag.
                actualDelay += 1;
            }

            // Add an admin log, using the "force feed" log type. It's not quite feeding, but the effect is the same.
            if (component.ToggleState == SharedInjectorComponent.InjectorToggleMode.Inject)
            {
                _logs.Add(LogType.ForceFeed,
                          $"{EntityManager.ToPrettyString(user):user} is attempting to inject {EntityManager.ToPrettyString(target):target} with a solution {SolutionContainerSystem.ToPrettyString(solution):solution}");
            }
        }
        else
        {
            // Self-injections take half as long.
            actualDelay /= 2;

            if (component.ToggleState == SharedInjectorComponent.InjectorToggleMode.Inject)
            {
                _logs.Add(LogType.Ingestion,
                          $"{EntityManager.ToPrettyString(user):user} is attempting to inject themselves with a solution {SolutionContainerSystem.ToPrettyString(solution):solution}.");
            }
        }

        component.CancelToken = new CancellationTokenSource();

        _doAfter.DoAfter(new DoAfterEventArgs(user, actualDelay, component.CancelToken.Token, target)
        {
            BreakOnUserMove        = true,
            BreakOnDamage          = true,
            BreakOnStun            = true,
            BreakOnTargetMove      = true,
            MovementThreshold      = 0.1f,
            BroadcastFinishedEvent = new InjectionCompleteEvent()
            {
                Component = component,
                User      = user,
                Target    = target,
            },
            BroadcastCancelledEvent = new InjectionCancelledEvent()
            {
                Component = component,
            }
        });
    }
示例#7
0
        /// <summary>
        ///     Attempt to force someone else to drink some of a drink. Returns true if any interaction took place,
        ///     including generation of pop-up messages.
        /// </summary>
        private bool TryForceDrink(EntityUid uid, EntityUid userUid, EntityUid targetUid,
                                   DrinkComponent?drink = null)
        {
            if (!Resolve(uid, ref drink))
            {
                return(false);
            }

            // cannot stack do-afters
            if (drink.CancelToken != null)
            {
                drink.CancelToken.Cancel();
                drink.CancelToken = null;
                return(true);
            }

            if (!EntityManager.HasComponent <SharedBodyComponent>(targetUid))
            {
                return(false);
            }

            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 (!_solutionContainerSystem.TryGetDrainableSolution(uid, 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 (_foodSystem.IsMouthBlocked(targetUid, userUid))
            {
                return(true);
            }

            EntityManager.TryGetComponent(userUid, out MetaDataComponent? meta);
            var userName = meta?.EntityName ?? string.Empty;

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

            drink.CancelToken = new();
            _doAfterSystem.DoAfter(new DoAfterEventArgs(userUid, drink.ForceFeedDelay, drink.CancelToken.Token, targetUid)
            {
                BreakOnUserMove         = true,
                BreakOnDamage           = true,
                BreakOnStun             = true,
                BreakOnTargetMove       = true,
                MovementThreshold       = 1.0f,
                TargetFinishedEvent     = new ForceDrinkEvent(userUid, drink, drinkSolution),
                BroadcastCancelledEvent = new ForceDrinkCancelledEvent(drink),
            });

            // logging
            _logSystem.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(userUid):user} is forcing {ToPrettyString(targetUid):target} to drink {ToPrettyString(uid):drink} {SolutionContainerSystem.ToPrettyString(drinkSolution):solution}");

            return(true);
        }
示例#8
0
        /// <summary>
        ///     Attempts to force feed a target. Returns true if any interaction occurred, including pop-up generation
        /// </summary>
        public bool TryForceFeed(EntityUid uid, EntityUid user, EntityUid target, FoodComponent?food = null)
        {
            if (!Resolve(uid, ref food))
            {
                return(false);
            }

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

            if (!EntityManager.HasComponent <SharedBodyComponent>(target))
            {
                return(false);
            }

            if (!_solutionContainerSystem.TryGetSolution(uid, food.SolutionName, out var foodSolution))
            {
                return(false);
            }

            if (food.UsesRemaining <= 0)
            {
                _popupSystem.PopupEntity(Loc.GetString("food-system-try-use-food-is-empty",
                                                       ("entity", uid)), user, Filter.Entities(user));
                DeleteAndSpawnTrash(food, user);
                return(true);
            }

            if (IsMouthBlocked(target, user))
            {
                return(true);
            }

            if (!TryGetRequiredUtensils(user, food, out var utensils))
            {
                return(true);
            }

            EntityManager.TryGetComponent(user, out MetaDataComponent? meta);
            var userName = meta?.EntityName ?? string.Empty;

            _popupSystem.PopupEntity(Loc.GetString("food-system-force-feed", ("user", userName)),
                                     user, Filter.Entities(target));

            food.CancelToken = new();
            _doAfterSystem.DoAfter(new DoAfterEventArgs(user, food.ForceFeedDelay, food.CancelToken.Token, target)
            {
                BreakOnUserMove         = true,
                BreakOnDamage           = true,
                BreakOnStun             = true,
                BreakOnTargetMove       = true,
                MovementThreshold       = 1.0f,
                TargetFinishedEvent     = new ForceFeedEvent(user, food, foodSolution, utensils),
                BroadcastCancelledEvent = new ForceFeedCancelledEvent(food)
            });

            // logging
            _logSystem.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(user):user} is forcing {ToPrettyString(target):target} to eat {ToPrettyString(uid):food} {SolutionContainerSystem.ToPrettyString(foodSolution):solution}");

            return(true);
        }