Exemple #1
0
        public void StartOpeningStripper(EntityUid user, StrippableComponent component)
        {
            if (component.CancelTokens.ContainsKey(user))
            {
                return;
            }

            if (TryComp <ActorComponent>(user, out var actor))
            {
                if (component.Owner.GetUIOrNull(StrippingUiKey.Key)?.SessionHasOpen(actor.PlayerSession) == true)
                {
                    return;
                }
            }

            var token = new CancellationTokenSource();

            var doAfterArgs = new DoAfterEventArgs(user, component.OpenDelay, token.Token, component.Owner)
            {
                BreakOnStun          = true,
                BreakOnDamage        = true,
                BreakOnTargetMove    = true,
                BreakOnUserMove      = true,
                NeedHand             = true,
                TargetCancelledEvent = new OpenStrippingCancelledEvent(user),
                TargetFinishedEvent  = new OpenStrippingCompleteEvent(user),
            };

            component.CancelTokens[user] = token;
            _doAfterSystem.DoAfter(doAfterArgs);
        }
 // construct the doafter and start it
 private void StartListening(EntityUid user, EntityUid target, StethoscopeComponent comp)
 {
     comp.CancelToken = new CancellationTokenSource();
     _doAfterSystem.DoAfter(new DoAfterEventArgs(user, comp.Delay, comp.CancelToken.Token, target: target)
     {
         BroadcastFinishedEvent  = new ListenSuccessfulEvent(user, target, comp),
         BroadcastCancelledEvent = new ListenCancelledEvent(user, comp),
         BreakOnTargetMove       = true,
         BreakOnUserMove         = true,
         BreakOnStun             = true,
         NeedHand = true
     });
 }
        /// <summary>
        ///     Sync version of UseTool.
        /// </summary>
        /// <param name="tool">The tool entity.</param>
        /// <param name="user">The entity using the tool.</param>
        /// <param name="target">Optionally, a target to use the tool on.</param>
        /// <param name="fuel">An optional amount of fuel or energy to consume-</param>
        /// <param name="doAfterDelay">A doAfter delay in seconds.</param>
        /// <param name="toolQualitiesNeeded">The tool qualities needed to use the tool.</param>
        /// <param name="doAfterCompleteEvent">An event to raise once the doAfter is completed successfully.</param>
        /// <param name="doAfterCancelledEvent">An event to raise once the doAfter is canceled.</param>
        /// <param name="doAfterEventTarget">Where to direct the do-after events. If null, events are broadcast</param>
        /// <param name="doAfterCheck">An optional check to perform for the doAfter.</param>
        /// <param name="toolComponent">The tool component.</param>
        /// <param name="cancelToken">Token to provide to do_after for cancelling</param>
        /// <returns>Whether initially, using the tool succeeded. If there's a doAfter delay, you'll need to listen to
        ///          the <see cref="doAfterCompleteEvent"/> and <see cref="doAfterCancelledEvent"/> being broadcast
        ///          to see whether using the tool succeeded or not. If the <see cref="doAfterDelay"/> is zero,
        ///          this simply returns whether using the tool succeeded or not.</returns>
        public bool UseTool(
            EntityUid tool,
            EntityUid user,
            EntityUid?target,
            float fuel,
            float doAfterDelay,
            IEnumerable <string> toolQualitiesNeeded,
            object?doAfterCompleteEvent   = null,
            object?doAfterCancelledEvent  = null,
            EntityUid?doAfterEventTarget  = null,
            Func <bool>?doAfterCheck      = null,
            ToolComponent?toolComponent   = null,
            CancellationToken?cancelToken = null)
        {
            // No logging here, after all that'd mean the caller would need to check if the component is there or not.
            if (!Resolve(tool, ref toolComponent, false))
            {
                return(false);
            }

            if (!ToolStartUse(tool, user, fuel, toolQualitiesNeeded, toolComponent))
            {
                return(false);
            }

            if (doAfterDelay > 0f)
            {
                var doAfterArgs = new DoAfterEventArgs(user, doAfterDelay / toolComponent.SpeedModifier, cancelToken ?? default, target)
                {
                    ExtraCheck              = doAfterCheck,
                    BreakOnDamage           = true,
                    BreakOnStun             = true,
                    BreakOnTargetMove       = true,
                    BreakOnUserMove         = true,
                    NeedHand                = true,
                    BroadcastFinishedEvent  = doAfterCompleteEvent != null ? new ToolDoAfterComplete(doAfterCompleteEvent, doAfterCancelledEvent, tool, user, fuel, doAfterEventTarget) : null,
                    BroadcastCancelledEvent = doAfterCancelledEvent != null ? new ToolDoAfterCancelled(doAfterCancelledEvent, doAfterEventTarget) : null,
                };

                _doAfterSystem.DoAfter(doAfterArgs);
                return(true);
            }

            return(ToolFinishUse(tool, user, fuel, toolComponent));
        }
        private void DisarmBombDoafter(EntityUid uid, EntityUid user, NukeComponent nuke)
        {
            nuke.DisarmCancelToken = new();
            var doafter = new DoAfterEventArgs(user, nuke.DisarmDoafterLength, nuke.DisarmCancelToken.Value, uid)
            {
                TargetCancelledEvent = new NukeDisarmCancelledEvent(),
                TargetFinishedEvent  = new NukeDisarmSuccessEvent(),
                BreakOnDamage        = true,
                BreakOnStun          = true,
                BreakOnTargetMove    = true,
                BreakOnUserMove      = true,
                NeedHand             = true,
            };

            _doAfterSystem.DoAfter(doafter);
            _popups.PopupEntity(Loc.GetString("nuke-component-doafter-warning"), user,
                                Filter.Entities(user), PopupType.LargeCaution);
        }
Exemple #5
0
        async Task <bool> IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
        {
            //No changing mode mid-RCD
            var startingMode = _mode;

            var mapGrid = _mapManager.GetGrid(eventArgs.ClickLocation.GetGridId(Owner.EntityManager));
            var tile    = mapGrid.GetTileRef(eventArgs.ClickLocation);
            var snapPos = mapGrid.SnapGridCellFor(eventArgs.ClickLocation, SnapGridOffset.Center);

            //Using an RCD isn't instantaneous
            var cancelToken      = new CancellationTokenSource();
            var doAfterEventArgs = new DoAfterEventArgs(eventArgs.User, _delay, cancelToken.Token, eventArgs.Target)
            {
                BreakOnDamage = true,
                BreakOnStun   = true,
                NeedHand      = true,
                ExtraCheck    = () => IsRCDStillValid(eventArgs, mapGrid, tile, snapPos, startingMode) //All of the sanity checks are here
            };

            var result = await doAfterSystem.DoAfter(doAfterEventArgs);

            if (result == DoAfterStatus.Cancelled)
            {
                return(true);
            }

            switch (_mode)
            {
            //Floor mode just needs the tile to be a space tile (subFloor)
            case RcdMode.Floors:
                mapGrid.SetTile(eventArgs.ClickLocation, new Tile(_tileDefinitionManager["floor_steel"].TileId));
                break;

            //We don't want to place a space tile on something that's already a space tile. Let's do the inverse of the last check.
            case RcdMode.Deconstruct:
                if (!tile.IsBlockedTurf(true))     //Delete the turf
                {
                    mapGrid.SetTile(snapPos, Tile.Empty);
                }
                else     //Delete what the user targeted
                {
                    eventArgs.Target.Delete();
                }
                break;

            //Walls are a special behaviour, and require us to build a new object with a transform rather than setting a grid tile, thus we early return to avoid the tile set code.
            case RcdMode.Walls:
                var ent = _serverEntityManager.SpawnEntity("solid_wall", mapGrid.GridTileToLocal(snapPos));
                ent.Transform.LocalRotation = Owner.Transform.LocalRotation;     //Now apply icon smoothing.
                break;

            case RcdMode.Airlock:
                var airlock = _serverEntityManager.SpawnEntity("Airlock", mapGrid.GridTileToLocal(snapPos));
                airlock.Transform.LocalRotation = Owner.Transform.LocalRotation;     //Now apply icon smoothing.
                break;

            default:
                return(true);    //I don't know why this would happen, but sure I guess. Get out of here invalid state!
            }

            _entitySystemManager.GetEntitySystem <AudioSystem>().PlayFromEntity("/Audio/Items/deconstruct.ogg", Owner);
            _ammo--;
            return(true);
        }
        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);
        }
Exemple #8
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);
        }
        /// <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, $"{user} is forcing {target} to eat {uid}");

            return(true);
        }