コード例 #1
0
ファイル: AudioSystem.cs プロジェクト: Visne/RobustToolbox
        /// <inheritdoc />
        public IPlayingAudioStream Play(Filter playerFilter, string filename, EntityCoordinates coordinates, AudioParams?audioParams = null)
        {
            //TODO: Calculate this from PAS
            var range = audioParams is null || audioParams.Value.MaxDistance <= 0 ? AudioDistanceRange : audioParams.Value.MaxDistance;

            var id = CacheIdentifier();

            var fallbackCoordinates = GetFallbackCoordinates(coordinates.ToMap(_entityManager));

            var msg = new PlayAudioPositionalMessage
            {
                FileName            = filename,
                Coordinates         = coordinates,
                FallbackCoordinates = fallbackCoordinates,
                AudioParams         = audioParams ?? AudioParams.Default,
                Identifier          = id
            };

            // We clone the filter here as to not modify the original instance.
            if (range > 0.0f)
            {
                playerFilter = playerFilter.Clone().AddInRange(coordinates.ToMap(EntityManager), range);
            }

            RaiseNetworkEvent(msg, playerFilter);

            return(new AudioSourceServer(this, id, playerFilter.Recipients.ToArray()));
        }
コード例 #2
0
        public static bool InRangeUnOccluded(IEntity origin, EntityCoordinates other, float range, Ignored?predicate, bool ignoreInsideBlocker = true)
        {
            var originPos = origin.Transform.MapPosition;
            var otherPos  = other.ToMap(origin.EntityManager);

            return(InRangeUnOccluded(originPos, otherPos, range, predicate, ignoreInsideBlocker));
        }
コード例 #3
0
        /// <inheritdoc />
        public IPlayingAudioStream Play(Filter playerFilter, string filename, EntityCoordinates coordinates, AudioParams?audioParams = null)
        {
            //TODO: Calculate this from PAS
            var range = audioParams is null || audioParams.Value.MaxDistance <= 0 ? AudioDistanceRange : audioParams.Value.MaxDistance;

            var id  = CacheIdentifier();
            var msg = new PlayAudioPositionalMessage
            {
                FileName    = filename,
                Coordinates = coordinates,
                AudioParams = audioParams ?? AudioParams.Default,
                Identifier  = id
            };

            IList <ICommonSession> players;
            var recipients = (playerFilter as IFilter).Recipients;

            if (range > 0.0f)
            {
                players = PasInRange(recipients, coordinates.ToMap(EntityManager), range);
            }
            else
            {
                players = recipients;
            }

            foreach (var player in players)
            {
                RaiseNetworkEvent(msg, player.ConnectedClient);
            }

            return(new AudioSourceServer(this, id, players));
        }
コード例 #4
0
        public static bool InRangeUnOccluded(EntityUid origin, EntityCoordinates other, float range, Ignored?predicate, bool ignoreInsideBlocker = true)
        {
            var entMan    = IoCManager.Resolve <IEntityManager>();
            var originPos = entMan.GetComponent <TransformComponent>(origin).MapPosition;
            var otherPos  = other.ToMap(entMan);

            return(InRangeUnOccluded(originPos, otherPos, range, predicate, ignoreInsideBlocker));
        }
コード例 #5
0
        /// <summary>
        ///     Returns the tile ref for a grid, or a map.
        /// </summary>
        public TileRef GetTileRef(EntityCoordinates coordinates)
        {
            var mapCoords = coordinates.ToMap(pManager.EntityManager);
            var gridId    = coordinates.GetGridId(pManager.EntityManager);

            return(gridId.IsValid() ? pManager.MapManager.GetGrid(gridId).GetTileRef(MouseCoords)
                : new TileRef(mapCoords.MapId, gridId,
                              MouseCoords.ToVector2i(pManager.EntityManager, pManager.MapManager), Tile.Empty));
        }
コード例 #6
0
 /// <summary>
 ///     Checks that an entity and a set of grid 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 grid coordinates to use.</param>
 /// <param name="range">
 ///     Maximum distance between the two entity and set of grid 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,
     EntityCoordinates other,
     float range = InteractionRange,
     CollisionGroup collisionMask = CollisionGroup.Impassable,
     Ignored?predicate            = null,
     bool popup = false)
 {
     return(InRangeUnobstructed(origin, other.ToMap(EntityManager), range, collisionMask, predicate, popup));
 }
コード例 #7
0
        public GridTargetSteeringRequest(EntityCoordinates targetGrid, float arrivalDistance, float pathfindingProximity = 0.5f, bool requiresInRangeUnobstructed = false)
        {
            // Get it once up front so we the manager doesn't have to continuously get it
            var entityManager = IoCManager.Resolve <IEntityManager>();

            TargetMap                   = targetGrid.ToMap(entityManager);
            TargetGrid                  = targetGrid;
            ArrivalDistance             = arrivalDistance;
            PathfindingProximity        = pathfindingProximity;
            RequiresInRangeUnobstructed = requiresInRangeUnobstructed;
        }
コード例 #8
0
        private bool OnCopy(ICommonSession?session, EntityCoordinates coords, EntityUid uid)
        {
            if (!CanSandbox())
            {
                return(false);
            }

            // Try copy entity.
            if (uid.IsValid() &&
                EntityManager.TryGetComponent(uid, out MetaDataComponent? comp) &&
                !comp.EntityDeleted)
            {
                if (comp.EntityPrototype == null || comp.EntityPrototype.NoSpawn || comp.EntityPrototype.Abstract)
                {
                    return(false);
                }

                if (_placementManager.Eraser)
                {
                    _placementManager.ToggleEraser();
                }

                _placementManager.BeginPlacing(new()
                {
                    EntityType      = comp.EntityPrototype.ID,
                    IsTile          = false,
                    TileType        = 0,
                    PlacementOption = comp.EntityPrototype.PlacementMode
                });
                return(true);
            }

            // Try copy tile.
            if (!_mapManager.TryFindGridAt(coords.ToMap(EntityManager), out var grid) || !grid.TryGetTileRef(coords, out var tileRef))
            {
                return(false);
            }

            if (_placementManager.Eraser)
            {
                _placementManager.ToggleEraser();
            }

            _placementManager.BeginPlacing(new()
            {
                EntityType      = null,
                IsTile          = true,
                TileType        = tileRef.Tile.TypeId,
                PlacementOption = nameof(AlignTileAny)
            });
            return(true);
        }
コード例 #9
0
        public static bool InRangeUnOccluded(
            this EntityCoordinates origin,
            IContainer other,
            float range              = InteractionRange,
            Ignored?predicate        = null,
            bool ignoreInsideBlocker = true)
        {
            var originPosition = origin.ToMap(other.Owner.EntityManager);
            var otherPosition  = other.Owner.Transform.MapPosition;

            return(ExamineSystemShared.InRangeUnOccluded(originPosition, otherPosition, range,
                                                         predicate, ignoreInsideBlocker));
        }
コード例 #10
0
        public static bool InRangeUnobstructed(
            this EntityCoordinates origin,
            IContainer other,
            float range = InteractionRange,
            CollisionGroup collisionMask = CollisionGroup.Impassable,
            Ignored?predicate            = null,
            bool ignoreInsideBlocker     = false)
        {
            var originPosition = origin.ToMap(IoCManager.Resolve <IEntityManager>());
            var otherPosition  = IoCManager.Resolve <IEntityManager>().GetComponent <TransformComponent>(other.Owner).MapPosition;

            return(SharedInteractionSystem.InRangeUnobstructed(originPosition, otherPosition, range, collisionMask,
                                                               predicate, ignoreInsideBlocker));
        }
コード例 #11
0
        public static bool InRangeUnOccluded(
            this EntityCoordinates origin,
            IContainer other,
            float range              = InteractionRange,
            Ignored?predicate        = null,
            bool ignoreInsideBlocker = true)
        {
            var entMan         = IoCManager.Resolve <IEntityManager>();
            var originPosition = origin.ToMap(entMan);
            var otherPosition  = entMan.GetComponent <TransformComponent>(other.Owner).MapPosition;

            return(ExamineSystemShared.InRangeUnOccluded(originPosition, otherPosition, range,
                                                         predicate, ignoreInsideBlocker));
        }
コード例 #12
0
        public static bool InRangeUnobstructed(
            this EntityCoordinates origin,
            IEntity other,
            float range = InteractionRange,
            CollisionGroup collisionMask = CollisionGroup.Impassable,
            Ignored?predicate            = null,
            bool ignoreInsideBlocker     = false)
        {
            var originPosition = origin.ToMap(other.EntityManager);
            var otherPosition  = other.Transform.MapPosition;

            return(SharedInteractionSystem.InRangeUnobstructed(originPosition, otherPosition, range, collisionMask,
                                                               predicate, ignoreInsideBlocker));
        }
コード例 #13
0
        public static bool InRangeUnobstructed(
            this MapCoordinates origin,
            EntityCoordinates other,
            float range = InteractionRange,
            CollisionGroup collisionMask = CollisionGroup.Impassable,
            Ignored predicate            = null,
            bool ignoreInsideBlocker     = false)
        {
            var entityManager = IoCManager.Resolve <IEntityManager>();
            var otherPosition = other.ToMap(entityManager);

            return(SharedInteractionSystem.InRangeUnobstructed(origin, otherPosition, range, collisionMask, predicate,
                                                               ignoreInsideBlocker));
        }
コード例 #14
0
        public bool IsColliding(EntityCoordinates coordinates)
        {
            var bounds    = pManager.ColliderAABB;
            var mapCoords = coordinates.ToMap(pManager.EntityManager);

            var(x, y) = mapCoords.Position;

            var collisionBox = Box2.FromDimensions(
                bounds.Left + x,
                bounds.Bottom + y,
                bounds.Width,
                bounds.Height);

            return(pManager.PhysicsManager.TryCollideRect(collisionBox, mapCoords.MapId));
        }
コード例 #15
0
        public static bool InRangeUnOccluded(
            this MapCoordinates origin,
            EntityCoordinates other,
            float range                  = InteractionRange,
            Ignored?predicate            = null,
            bool ignoreInsideBlocker     = true,
            IEntityManager?entityManager = null)
        {
            IoCManager.Resolve(ref entityManager);

            var otherPosition = other.ToMap(entityManager);

            return(ExamineSystemShared.InRangeUnOccluded(origin, otherPosition, range, predicate,
                                                         ignoreInsideBlocker));
        }
コード例 #16
0
        /// <inheritdoc />
        public IEnumerable <IEntity> GetEntitiesInArc(EntityCoordinates coordinates, float range, Angle direction,
                                                      float arcWidth, bool approximate = false)
        {
            var position = coordinates.ToMap(this).Position;

            foreach (var entity in GetEntitiesInRange(coordinates, range * 2, approximate))
            {
                var angle = new Angle(entity.Transform.WorldPosition - position);
                if (angle.Degrees < direction.Degrees + arcWidth / 2 &&
                    angle.Degrees > direction.Degrees - arcWidth / 2)
                {
                    yield return(entity);
                }
            }
        }
コード例 #17
0
        public bool Condition(EntityUid user, EntityCoordinates location, Direction direction)
        {
            var entManager = IoCManager.Resolve <IEntityManager>();

            // get blueprint and user position
            var userWorldPosition = entManager.GetComponent <TransformComponent>(user).WorldPosition;
            var objWorldPosition  = location.ToMap(entManager).Position;

            // find direction from user to blueprint
            var userToObject = (objWorldPosition - userWorldPosition);
            // get direction of the grid being placed on as an offset.
            var gridRotation        = entManager.GetComponent <TransformComponent>(location.EntityId).WorldRotation;
            var directionWithOffset = gridRotation.RotateVec(direction.ToVec());

            // dot product will be positive if user direction and blueprint are co-directed
            var dotProd = Vector2.Dot(directionWithOffset.Normalized, userToObject.Normalized);

            if (dotProd > 0)
            {
                return(false);
            }

            // now we need to check that user actually tries to build wallmount on a wall
            var physics    = EntitySystem.Get <SharedPhysicsSystem>();
            var rUserToObj = new CollisionRay(userWorldPosition, userToObject.Normalized, (int)CollisionGroup.Impassable);
            var length     = userToObject.Length;

            var tagSystem = EntitySystem.Get <TagSystem>();

            var userToObjRaycastResults = physics.IntersectRayWithPredicate(entManager.GetComponent <TransformComponent>(user).MapID, rUserToObj, maxLength: length,
                                                                            predicate: (e) => !tagSystem.HasTag(e, "Wall"));

            var targetWall = userToObjRaycastResults.FirstOrNull();

            if (targetWall == null)
            {
                return(false);
            }

            // get this wall entity
            // check that we didn't try to build wallmount that facing another adjacent wall
            var rAdjWall = new CollisionRay(objWorldPosition, directionWithOffset.Normalized, (int)CollisionGroup.Impassable);
            var adjWallRaycastResults = physics.IntersectRayWithPredicate(entManager.GetComponent <TransformComponent>(user).MapID, rAdjWall, maxLength: 0.5f,
                                                                          predicate: (e) => e == targetWall.Value.HitEntity || !tagSystem.HasTag(e, "Wall"));

            return(!adjWallRaycastResults.Any());
        }
コード例 #18
0
ファイル: AudioSystem.cs プロジェクト: Zumorica/RobustToolbox
        /// <inheritdoc />
        public IPlayingAudioStream Play(Filter playerFilter, string filename, EntityCoordinates coordinates, AudioParams?audioParams = null)
        {
            var id = CacheIdentifier();

            var fallbackCoordinates = GetFallbackCoordinates(coordinates.ToMap(_entityManager));

            var msg = new PlayAudioPositionalMessage
            {
                FileName            = filename,
                Coordinates         = coordinates,
                FallbackCoordinates = fallbackCoordinates,
                AudioParams         = audioParams ?? AudioParams.Default,
                Identifier          = id
            };

            RaiseNetworkEvent(msg, playerFilter);

            return(new AudioSourceServer(this, id, playerFilter.Recipients.ToArray()));
        }
コード例 #19
0
        public bool Condition(IEntity user, EntityCoordinates location, Direction direction)
        {
            var entManager = IoCManager.Resolve <IEntityManager>();

            // get blueprint and user position
            var userWorldPosition = user.Transform.WorldPosition;
            var objWorldPosition  = location.ToMap(entManager).Position;

            // find direction from user to blueprint
            var userToObject = (objWorldPosition - userWorldPosition);

            // dot product will be positive if user direction and blueprint are co-directed
            var dotProd = Vector2.Dot(direction.ToVec(), userToObject);

            if (dotProd > 0)
            {
                return(false);
            }

            // now we need to check that user actually tries to build wallmount on a wall
            var physics    = EntitySystem.Get <SharedBroadphaseSystem>();
            var rUserToObj = new CollisionRay(userWorldPosition, userToObject.Normalized, (int)CollisionGroup.Impassable);
            var length     = userToObject.Length;
            var userToObjRaycastResults = physics.IntersectRayWithPredicate(user.Transform.MapID, rUserToObj, maxLength: length,
                                                                            predicate: (e) => !e.HasTag("Wall"));

            if (!userToObjRaycastResults.Any())
            {
                return(false);
            }

            // get this wall entity
            var targetWall = userToObjRaycastResults.First().HitEntity;

            // check that we didn't try to build wallmount that facing another adjacent wall
            var rAdjWall = new CollisionRay(objWorldPosition, direction.ToVec(), (int)CollisionGroup.Impassable);
            var adjWallRaycastResults = physics.IntersectRayWithPredicate(user.Transform.MapID, rAdjWall, maxLength: 0.5f,
                                                                          predicate: (e) => e == targetWall || !e.HasTag("Wall"));

            return(!adjWallRaycastResults.Any());
        }
コード例 #20
0
        /// <summary>
        ///     Checks that an entity and a set of grid 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 grid coordinates to use.</param>
        /// <param name="range">
        ///     Maximum distance between the two entity and set of grid 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="ignoreInsideBlocker">
        ///     If true and <see cref="origin"/> or <see cref="other"/> are inside
        ///     the obstruction, ignores the obstruction and considers the interaction
        ///     unobstructed.
        ///     Therefore, setting this to true makes this check more permissive,
        ///     such as allowing an interaction to occur inside something impassable
        ///     (like a wall). The default, false, makes the check more restrictive.
        /// </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(
            IEntity origin,
            EntityCoordinates other,
            float range = InteractionRange,
            CollisionGroup collisionMask = CollisionGroup.Impassable,
            Ignored?predicate            = null,
            bool ignoreInsideBlocker     = false,
            bool popup = false)
        {
            var originPosition = origin.Transform.MapPosition;
            var otherPosition  = other.ToMap(EntityManager);

            predicate ??= e => e == origin;

            var inRange = InRangeUnobstructed(originPosition, otherPosition, range, collisionMask, predicate, ignoreInsideBlocker);

            if (!inRange && popup)
            {
                var message = Loc.GetString("You can't reach there!");
                origin.PopupMessage(message);
            }

            return(inRange);
        }
コード例 #21
0
 public IGridAtmosphereComponent GetGridAtmosphere(EntityCoordinates coordinates)
 {
     return(GetGridAtmosphere(coordinates.ToMap(EntityManager)));
 }
コード例 #22
0
        /// <inheritdoc />
        public IEnumerable <IEntity> GetEntitiesIntersecting(EntityCoordinates position, bool approximate = false)
        {
            var mapPos = position.ToMap(this);

            return(GetEntitiesIntersecting(mapPos.MapId, mapPos.Position, approximate));
        }
コード例 #23
0
    public override void Shoot(GunComponent gun, List <IShootable> ammo, EntityCoordinates fromCoordinates, EntityCoordinates toCoordinates, EntityUid?user = null)
    {
        var fromMap      = fromCoordinates.ToMap(EntityManager);
        var toMap        = toCoordinates.ToMapPos(EntityManager);
        var mapDirection = toMap - fromMap.Position;
        var mapAngle     = mapDirection.ToAngle();
        var angle        = GetRecoilAngle(Timing.CurTime, gun, mapDirection.ToAngle());

        // Update shot based on the recoil
        toMap        = fromMap.Position + angle.ToVec() * mapDirection.Length;
        mapDirection = toMap - fromMap.Position;
        var entityDirection = Transform(fromCoordinates.EntityId).InvWorldMatrix.Transform(toMap) - fromCoordinates.Position;

        // I must be high because this was getting tripped even when true.
        // DebugTools.Assert(direction != Vector2.Zero);
        var shotProjectiles = new List <EntityUid>(ammo.Count);

        foreach (var shootable in ammo)
        {
            switch (shootable)
            {
            // Cartridge shoots something else
            case CartridgeAmmoComponent cartridge:
                if (!cartridge.Spent)
                {
                    if (cartridge.Count > 1)
                    {
                        var angles = LinearSpread(mapAngle - cartridge.Spread / 2,
                                                  mapAngle + cartridge.Spread / 2, cartridge.Count);

                        for (var i = 0; i < cartridge.Count; i++)
                        {
                            var uid = Spawn(cartridge.Prototype, fromCoordinates);
                            ShootProjectile(uid, angles[i].ToVec(), user);
                            shotProjectiles.Add(uid);
                        }
                    }
                    else
                    {
                        var uid = Spawn(cartridge.Prototype, fromCoordinates);
                        ShootProjectile(uid, mapDirection, user);
                        shotProjectiles.Add(uid);
                    }

                    SetCartridgeSpent(cartridge, true);
                    MuzzleFlash(gun.Owner, cartridge, user);
                    PlaySound(gun.Owner, gun.SoundGunshot?.GetSound(Random, ProtoManager), user);

                    if (cartridge.DeleteOnSpawn)
                    {
                        Del(cartridge.Owner);
                    }
                }
                else
                {
                    PlaySound(gun.Owner, gun.SoundEmpty?.GetSound(Random, ProtoManager), user);
                }

                // Something like ballistic might want to leave it in the container still
                if (!cartridge.DeleteOnSpawn && !Containers.IsEntityInContainer(cartridge.Owner))
                {
                    EjectCartridge(cartridge.Owner);
                }

                Dirty(cartridge);
                break;

            // Ammo shoots itself
            case AmmoComponent newAmmo:
                shotProjectiles.Add(newAmmo.Owner);
                MuzzleFlash(gun.Owner, newAmmo, user);
                PlaySound(gun.Owner, gun.SoundGunshot?.GetSound(Random, ProtoManager), user);

                // Do a throw
                if (!HasComp <ProjectileComponent>(newAmmo.Owner))
                {
                    RemComp <AmmoComponent>(newAmmo.Owner);
                    // TODO: Someone can probably yeet this a billion miles so need to pre-validate input somewhere up the call stack.
                    ThrowingSystem.TryThrow(newAmmo.Owner, mapDirection, 20f, user);
                    break;
                }

                ShootProjectile(newAmmo.Owner, mapDirection, user);
                break;

            case HitscanPrototype hitscan:
                var ray            = new CollisionRay(fromMap.Position, mapDirection.Normalized, hitscan.CollisionMask);
                var rayCastResults = Physics.IntersectRay(fromMap.MapId, ray, hitscan.MaxLength, user, false).ToList();

                if (rayCastResults.Count >= 1)
                {
                    var result   = rayCastResults[0];
                    var distance = result.Distance;
                    FireEffects(fromCoordinates, distance, entityDirection.ToAngle(), hitscan, result.HitEntity);

                    var dmg = hitscan.Damage;

                    if (dmg != null)
                    {
                        dmg = Damageable.TryChangeDamage(result.HitEntity, dmg);
                    }

                    if (dmg != null)
                    {
                        PlayImpactSound(result.HitEntity, dmg, hitscan.Sound, hitscan.ForceSound);

                        if (user != null)
                        {
                            Logs.Add(LogType.HitScanHit,
                                     $"{ToPrettyString(user.Value):user} hit {ToPrettyString(result.HitEntity):target} using hitscan and dealt {dmg.Total:damage} damage");
                        }
                        else
                        {
                            Logs.Add(LogType.HitScanHit,
                                     $"Hit {ToPrettyString(result.HitEntity):target} using hitscan and dealt {dmg.Total:damage} damage");
                        }
                    }
                }
                else
                {
                    FireEffects(fromCoordinates, hitscan.MaxLength, entityDirection.ToAngle(), hitscan);
                }
                PlaySound(gun.Owner, gun.SoundGunshot?.GetSound(Random, ProtoManager), user);
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
        }

        RaiseLocalEvent(gun.Owner, new AmmoShotEvent()
        {
            FiredProjectiles = shotProjectiles,
        }, false);
    }
コード例 #24
0
 /// <summary>
 ///     Gets all players inside of a circle.
 /// </summary>
 /// <param name="worldPos">Position of the circle in world-space.</param>
 /// <param name="range">Radius of the circle in world units.</param>
 /// <returns></returns>
 public List <IPlayerSession> GetPlayersInRange(EntityCoordinates worldPos, int range)
 {
     return(GetPlayersInRange(worldPos.ToMap(_entityManager), range));
 }
コード例 #25
0
 public IList <IEntity> GetEntitiesUnderPosition(EntityCoordinates coordinates)
 {
     return(GetEntitiesUnderPosition(coordinates.ToMap(EntityManager)));
 }