Пример #1
0
    protected override void OnCanDragDropOn(EntityUid uid, SharedClimbableComponent component, CanDragDropOnEvent args)
    {
        base.OnCanDragDropOn(uid, component, args);

        if (!args.CanDrop)
        {
            return;
        }

        var user    = args.User;
        var target  = args.Target;
        var dragged = args.Dragged;

        bool Ignored(EntityUid entity) => entity == target || entity == user || entity == dragged;

        args.CanDrop = _interactionSystem.InRangeUnobstructed(user, target, component.Range, predicate: Ignored) &&
                       _interactionSystem.InRangeUnobstructed(user, dragged, component.Range, predicate: Ignored);
        args.Handled = true;
    }
Пример #2
0
        /// <summary>
        /// Allows a user to pick up entities by clicking them, or pick up all entities in a certain radius
        /// around a click.
        /// </summary>
        /// <returns></returns>
        private async void AfterInteract(EntityUid uid, ServerStorageComponent storageComp, AfterInteractEvent eventArgs)
        {
            if (!eventArgs.CanReach)
            {
                return;
            }

            if (storageComp.CancelToken != null)
            {
                storageComp.CancelToken.Cancel();
                storageComp.CancelToken = null;
                return;
            }

            // Pick up all entities in a radius around the clicked location.
            // The last half of the if is because carpets exist and this is terrible
            if (storageComp.AreaInsert && (eventArgs.Target == null || !HasComp <ItemComponent>(eventArgs.Target.Value)))
            {
                var validStorables = new List <EntityUid>();
                foreach (var entity in _entityLookupSystem.GetEntitiesInRange(eventArgs.ClickLocation, storageComp.AreaInsertRadius, LookupFlags.None))
                {
                    if (entity == eventArgs.User ||
                        !HasComp <ItemComponent>(entity) ||
                        !_interactionSystem.InRangeUnobstructed(eventArgs.User, entity))
                    {
                        continue;
                    }

                    validStorables.Add(entity);
                }

                //If there's only one then let's be generous
                if (validStorables.Count > 1)
                {
                    storageComp.CancelToken = new CancellationTokenSource();
                    var doAfterArgs = new DoAfterEventArgs(eventArgs.User, 0.2f * validStorables.Count, storageComp.CancelToken.Token, uid)
                    {
                        BreakOnStun     = true,
                        BreakOnDamage   = true,
                        BreakOnUserMove = true,
                        NeedHand        = true,
                    };

                    await _doAfterSystem.WaitDoAfter(doAfterArgs);
                }

                // TODO: Make it use the event DoAfter
                var successfullyInserted          = new List <EntityUid>();
                var successfullyInsertedPositions = new List <EntityCoordinates>();
                foreach (var entity in validStorables)
                {
                    // Check again, situation may have changed for some entities, but we'll still pick up any that are valid
                    if (_containerSystem.IsEntityInContainer(entity) ||
                        entity == eventArgs.User ||
                        !HasComp <ItemComponent>(entity))
                    {
                        continue;
                    }

                    if (TryComp <TransformComponent>(uid, out var transformOwner) && TryComp <TransformComponent>(entity, out var transformEnt))
                    {
                        var position = EntityCoordinates.FromMap(transformOwner.Parent?.Owner ?? uid, transformEnt.MapPosition);

                        if (PlayerInsertEntityInWorld(uid, eventArgs.User, entity, storageComp))
                        {
                            successfullyInserted.Add(entity);
                            successfullyInsertedPositions.Add(position);
                        }
                    }
                }

                // If we picked up atleast one thing, play a sound and do a cool animation!
                if (successfullyInserted.Count > 0)
                {
                    if (storageComp.StorageInsertSound is not null)
                    {
                        SoundSystem.Play(storageComp.StorageInsertSound.GetSound(), Filter.Pvs(uid, entityManager: EntityManager), uid, AudioParams.Default);
                    }
                    RaiseNetworkEvent(new AnimateInsertingEntitiesEvent(uid, successfullyInserted, successfullyInsertedPositions));
                }
                return;
            }
            // Pick up the clicked entity
            else if (storageComp.QuickInsert)
            {
                if (eventArgs.Target is not {
                    Valid : true
                } target)
                {
                    return;
                }

                if (_containerSystem.IsEntityInContainer(target) ||
                    target == eventArgs.User ||
                    !HasComp <ItemComponent>(target))
                {
                    return;
                }

                if (TryComp <TransformComponent>(uid, out var transformOwner) && TryComp <TransformComponent>(target, out var transformEnt))
                {
                    var parent = transformOwner.ParentUid;

                    var position = EntityCoordinates.FromMap(
                        parent.IsValid() ? parent : uid,
                        transformEnt.MapPosition);
                    if (PlayerInsertEntityInWorld(uid, eventArgs.User, target, storageComp))
                    {
                        RaiseNetworkEvent(new AnimateInsertingEntitiesEvent(uid,
                                                                            new List <EntityUid> {
                            target
                        },
                                                                            new List <EntityCoordinates> {
                            position
                        }));
                    }
                }
            }
            return;
        }
Пример #3
0
        // TODO ECS BUCKLE/STRAP These 'Strap' verbs are an incestuous mess of buckle component and strap component
        // functions. Whenever these are fully ECSed, maybe do it in a way that allows for these verbs to be handled in
        // a sensible manner in a single system?

        private void AddStrapVerbs(EntityUid uid, StrapComponent component, GetVerbsEvent <InteractionVerb> args)
        {
            if (args.Hands == null || !args.CanAccess || !args.CanInteract || !component.Enabled)
            {
                return;
            }

            // Note that for whatever bloody reason, buckle component has its own interaction range. Additionally, this
            // range can be set per-component, so we have to check a modified InRangeUnobstructed for every verb.

            // Add unstrap verbs for every strapped entity.
            foreach (var entity in component.BuckledEntities)
            {
                var buckledComp = EntityManager.GetComponent <BuckleComponent>(entity);

                if (!_interactionSystem.InRangeUnobstructed(args.User, args.Target, range: buckledComp.Range))
                {
                    continue;
                }

                InteractionVerb verb = new()
                {
                    Act      = () => buckledComp.TryUnbuckle(args.User),
                    Category = VerbCategory.Unbuckle
                };

                if (entity == args.User)
                {
                    verb.Text = Loc.GetString("verb-self-target-pronoun");
                }
                else
                {
                    verb.Text = EntityManager.GetComponent <MetaDataComponent>(entity).EntityName;
                }

                // In the event that you have more than once entity with the same name strapped to the same object,
                // these two verbs will be identical according to Verb.CompareTo, and only one with actually be added to
                // the verb list. However this should rarely ever be a problem. If it ever is, it could be fixed by
                // appending an integer to verb.Text to distinguish the verbs.

                args.Verbs.Add(verb);
            }

            // Add a verb to buckle the user.
            if (EntityManager.TryGetComponent <BuckleComponent?>(args.User, out var buckle) &&
                buckle.BuckledTo != component &&
                args.User != component.Owner &&
                component.HasSpace(buckle) &&
                _interactionSystem.InRangeUnobstructed(args.User, args.Target, range: buckle.Range))
            {
                InteractionVerb verb = new()
                {
                    Act      = () => buckle.TryBuckle(args.User, args.Target),
                    Category = VerbCategory.Buckle,
                    Text     = Loc.GetString("verb-self-target-pronoun")
                };
                args.Verbs.Add(verb);
            }

            // If the user is currently holding/pulling an entity that can be buckled, add a verb for that.
            if (args.Using is { Valid : true } @using&&
                EntityManager.TryGetComponent <BuckleComponent?>(@using, out var usingBuckle) &&
                component.HasSpace(usingBuckle) &&
                _interactionSystem.InRangeUnobstructed(@using, args.Target, range : usingBuckle.Range))
            {
                // Check that the entity is unobstructed from the target (ignoring the user).
                bool Ignored(EntityUid entity) => entity == args.User || entity == args.Target || entity == @using;

                if (!_interactionSystem.InRangeUnobstructed(@using, args.Target, usingBuckle.Range, predicate: Ignored))
                {
                    return;
                }

                InteractionVerb verb = new()
                {
                    Act      = () => usingBuckle.TryBuckle(args.User, args.Target),
                    Category = VerbCategory.Buckle,
                    Text     = EntityManager.GetComponent <MetaDataComponent>(@using).EntityName,
                    // just a held object, the user is probably just trying to sit down.
                    // If the used entity is a person being pulled, prioritize this verb. Conversely, if it is
                    Priority = EntityManager.HasComponent <ActorComponent>(@using) ? 1 : -1
                };

                args.Verbs.Add(verb);
            }
        }