コード例 #1
0
        /// <summary>
        ///     Checks that two entities are within a certain distance without any
        ///     entity that matches the collision mask obstructing them.
        ///     If the <paramref name="range"/> is zero or negative,
        ///     this method will only check if nothing obstructs the two entities.
        ///     This function will also check whether the other entity is a wall-mounted entity. If it is, it will
        ///     automatically ignore some obstructions.
        /// </summary>
        /// <param name="origin">The first entity to use.</param>
        /// <param name="other">Other entity to use.</param>
        /// <param name="range">
        ///     Maximum distance between the two entities.
        /// </param>
        /// <param name="collisionMask">The mask to check for collisions.</param>
        /// <param name="predicate">
        ///     A predicate to check whether to ignore an entity or not.
        ///     If it returns true, it will be ignored.
        /// </param>
        /// <param name="popup">
        ///     Whether or not to popup a feedback message on the origin entity for
        ///     it to see.
        /// </param>
        /// <returns>
        ///     True if the two points are within a given range without being obstructed.
        /// </returns>
        public bool InRangeUnobstructed(
            EntityUid origin,
            EntityUid other,
            float range = InteractionRange,
            CollisionGroup collisionMask = CollisionGroup.Impassable,
            Ignored?predicate            = null,
            bool popup = false)
        {
            var originPosition = Transform(origin).MapPosition;
            var transform      = Transform(other);

            var(position, rotation) = transform.GetWorldPositionRotation();
            var mapPos        = new MapCoordinates(position, transform.MapID);
            var wallPredicate = AddAnchoredPredicate(other, mapPos, rotation, originPosition);

            Ignored combinedPredicate = e =>
            {
                return(e == origin ||
                       e == other ||
                       (predicate?.Invoke(e) ?? false) ||
                       (wallPredicate?.Invoke(e) ?? false));
            };

            var inRange = InRangeUnobstructed(origin, mapPos, range, collisionMask, combinedPredicate, popup);

            if (!inRange && popup && _gameTiming.IsFirstTimePredicted)
            {
                var message = Loc.GetString("interaction-system-user-interaction-cannot-reach");
                _popupSystem.PopupEntity(message, origin, Filter.Entities(origin));
            }

            return(inRange);
        }
コード例 #2
0
        public bool InRangeUnobstructed(
            MapCoordinates origin,
            EntityUid target,
            float range = InteractionRange,
            CollisionGroup collisionMask = InRangeUnobstructedMask,
            Ignored?predicate            = null)
        {
            var transform = Transform(target);

            var(position, rotation) = transform.GetWorldPositionRotation();
            var mapPos = new MapCoordinates(position, transform.MapID);

            HashSet <EntityUid> ignored = new();

            bool ignoreAnchored = false;

            if (HasComp <SharedItemComponent>(target) && TryComp(target, out PhysicsComponent? physics) && physics.CanCollide)
            {
                // If the target is an item, we ignore any colliding entities. Currently done so that if items get stuck
                // inside of walls, users can still pick them up.
                ignored.UnionWith(_sharedBroadphaseSystem.GetEntitiesIntersectingBody(target, (int)collisionMask, false, physics));
            }
            else if (TryComp(target, out WallMountComponent? wallMount))
            {
                // wall-mount exemptions may be restricted to a specific angle range.da

                if (wallMount.Arc >= Math.Tau)
                {
                    ignoreAnchored = true;
                }
                else
                {
                    var angle      = Angle.FromWorldVec(origin.Position - position);
                    var angleDelta = (wallMount.Direction + rotation - angle).Reduced().FlipPositive();
                    ignoreAnchored = angleDelta < wallMount.Arc / 2 || Math.Tau - angleDelta < wallMount.Arc / 2;
                }

                if (ignoreAnchored && _mapManager.TryFindGridAt(mapPos, out var grid))
                {
                    ignored.UnionWith(grid.GetAnchoredEntities(mapPos));
                }
            }

            Ignored combinedPredicate = e =>
            {
                return(e == target ||
                       (predicate?.Invoke(e) ?? false) ||
                       ignored.Contains(e));
            };

            return(InRangeUnobstructed(origin, mapPos, range, collisionMask, combinedPredicate));
        }
コード例 #3
0
        /// <summary>
        ///     Checks that an entity and a set of map coordinates are within a certain
        ///     distance without any entity that matches the collision mask
        ///     obstructing them.
        ///     If the <paramref name="range"/> is zero or negative,
        ///     this method will only check if nothing obstructs the entity and component.
        /// </summary>
        /// <param name="origin">The entity to use.</param>
        /// <param name="other">The map coordinates to use.</param>
        /// <param name="range">
        ///     Maximum distance between the two entity and set of map coordinates.
        /// </param>
        /// <param name="collisionMask">The mask to check for collisions.</param>
        /// <param name="predicate">
        ///     A predicate to check whether to ignore an entity or not.
        ///     If it returns true, it will be ignored.
        /// </param>
        /// <param name="popup">
        ///     Whether or not to popup a feedback message on the origin entity for
        ///     it to see.
        /// </param>
        /// <returns>
        ///     True if the two points are within a given range without being obstructed.
        /// </returns>
        public bool InRangeUnobstructed(
            EntityUid origin,
            MapCoordinates other,
            float range = InteractionRange,
            CollisionGroup collisionMask = CollisionGroup.Impassable,
            Ignored?predicate            = null,
            bool popup = false)
        {
            Ignored combinedPredicatre = e => e == origin || (predicate?.Invoke(e) ?? false);
            var     originPosition     = Transform(origin).MapPosition;
            var     inRange            = InRangeUnobstructed(originPosition, other, range, collisionMask, combinedPredicatre);

            if (!inRange && popup && _gameTiming.IsFirstTimePredicted)
            {
                var message = Loc.GetString("interaction-system-user-interaction-cannot-reach");
                _popupSystem.PopupEntity(message, origin, Filter.Entities(origin));
            }

            return(inRange);
        }
コード例 #4
0
        public bool InRangeUnobstructed(
            MapCoordinates origin,
            EntityUid target,
            float range = InteractionRange,
            CollisionGroup collisionMask = CollisionGroup.Impassable,
            Ignored?predicate            = null)
        {
            var transform = Transform(target);

            var(position, rotation) = transform.GetWorldPositionRotation();
            var mapPos = new MapCoordinates(position, transform.MapID);

            var     wallPredicate     = AddAnchoredPredicate(target, mapPos, rotation, origin);
            Ignored combinedPredicate = e =>
            {
                return(e == target ||
                       (predicate?.Invoke(e) ?? false) ||
                       (wallPredicate?.Invoke(e) ?? false));
            };

            return(InRangeUnobstructed(origin, mapPos, range, collisionMask, combinedPredicate));
        }
コード例 #5
0
 private void IgnoreClick(object sender, RoutedEventArgs e)
 {
     Ignored?.Invoke(this);
 }