예제 #1
0
        public static void Throw(IEntity thrownEnt, float throwForce, GridCoordinates targetLoc, GridCoordinates sourceLoc, bool spread = false, IEntity throwSourceEnt = null)
        {
            if (!thrownEnt.TryGetComponent(out CollidableComponent colComp))
            {
                return;
            }

            var mapManager = IoCManager.Resolve <IMapManager>();

            colComp.CollisionEnabled = true;
            // I can now collide with player, so that i can do damage.

            if (!thrownEnt.TryGetComponent(out ThrownItemComponent projComp))
            {
                projComp = thrownEnt.AddComponent <ThrownItemComponent>();

                if (colComp.PhysicsShapes.Count == 0)
                {
                    colComp.PhysicsShapes.Add(new PhysShapeAabb());
                }

                colComp.PhysicsShapes[0].CollisionMask |= (int)CollisionGroup.MobImpassable;
                colComp.IsScrapingFloor = false;
            }
            var angle = new Angle(targetLoc.ToMapPos(mapManager) - sourceLoc.ToMapPos(mapManager));

            if (spread)
            {
                var spreadRandom = IoCManager.Resolve <IRobustRandom>();
                angle += Angle.FromDegrees(spreadRandom.NextGaussian(0, 3));
            }

            if (throwSourceEnt != null)
            {
                projComp.User = throwSourceEnt;
                projComp.IgnoreEntity(throwSourceEnt);

                throwSourceEnt.Transform.LocalRotation = angle.GetCardinalDir().ToAngle();
            }

            if (!thrownEnt.TryGetComponent(out PhysicsComponent physComp))
            {
                physComp = thrownEnt.AddComponent <PhysicsComponent>();
            }

            // TODO: Move this into PhysicsSystem, we need an ApplyForce function.
            var a = throwForce / (float)Math.Max(0.001, physComp.Mass);  // a = f / m

            var timing = IoCManager.Resolve <IGameTiming>();
            var spd    = a / (1f / timing.TickRate); // acceleration is applied in 1 tick instead of 1 second, scale appropriately

            physComp.LinearVelocity = angle.ToVec() * spd;
        }
예제 #2
0
        public bool IsColliding(GridCoordinates coordinates)
        {
            var bounds = pManager.ColliderAABB;
            var worldcoords = coordinates.ToMapPos(pManager.MapManager);

            var collisionbox = Box2.FromDimensions(
                bounds.Left + worldcoords.X,
                bounds.Bottom + worldcoords.Y,
                bounds.Width,
                bounds.Height);

            if (pManager.PhysicsManager.TryCollideRect(collisionbox, pManager.MapManager.GetGrid(coordinates.GridID).ParentMapId))
                return true;

            return false;
        }
예제 #3
0
        /// <summary>
        ///     Play an audio stream at a static position.
        /// </summary>
        /// <param name="stream">The audio stream to play.</param>
        /// <param name="coordinates">The coordinates at which to play the audio.</param>
        /// <param name="audioParams"></param>
        public IPlayingAudioStream Play(AudioStream stream, GridCoordinates coordinates,
                                        AudioParams?audioParams = null)
        {
            var source = _clyde.CreateAudioSource(stream);

            source.SetPosition(coordinates.ToMapPos(_mapManager));
            ApplyAudioParams(audioParams, source);

            source.StartPlaying();
            var playing = new PlayingStream
            {
                Source = source,
                TrackingCoordinates = coordinates,
            };

            PlayingClydeStreams.Add(playing);
            return(playing);
        }
예제 #4
0
        /// <summary>
        ///     Throw an entity at the position of <paramref name="targetLoc"/> from <paramref name="sourceLoc"/>,
        ///     without overshooting.
        /// </summary>
        /// <param name="thrownEnt">The entity to throw.</param>
        /// <param name="throwForceMax">
        /// The MAXIMUM force to throw the entity with.
        /// Throw force increases with distance to target, this is the maximum force allowed.
        /// </param>
        /// <param name="targetLoc">
        /// The target location to throw at.
        /// This function will try to land at this exact spot,
        /// if <paramref name="throwForceMax"/> is large enough to allow for it to be reached.
        /// </param>
        /// <param name="sourceLoc">
        /// The position to start the throw from.
        /// </param>
        /// <param name="spread">
        /// If true, slightly spread the actual throw angle.
        /// </param>
        /// <param name="throwSourceEnt">
        /// The entity that did the throwing. An opposite impulse will be applied to this entity if passed in.
        /// </param>
        public static void ThrowTo(IEntity thrownEnt, float throwForceMax, GridCoordinates targetLoc,
                                   GridCoordinates sourceLoc, bool spread = false, IEntity throwSourceEnt = null)
        {
            var mapManager = IoCManager.Resolve <IMapManager>();
            var timing     = IoCManager.Resolve <IGameTiming>();

            // Calculate the force necessary to land a throw based on throw duration, mass and distance.
            var distance      = (targetLoc.ToMapPos(mapManager) - sourceLoc.ToMapPos(mapManager)).Length;
            var throwDuration = ThrowController.DefaultThrowTime;
            var mass          = 1f;

            if (thrownEnt.TryGetComponent(out PhysicsComponent physicsComponent))
            {
                mass = physicsComponent.Mass;
            }

            var velocityNecessary = distance / throwDuration;
            var impulseNecessary  = velocityNecessary * mass;
            var forceNecessary    = impulseNecessary * (1f / timing.TickRate);

            // Then clamp it to the max force allowed and call Throw().
            Throw(thrownEnt, Math.Min(forceNecessary, throwForceMax), targetLoc, sourceLoc, spread, throwSourceEnt);
        }
예제 #5
0
        /// <summary>
        ///     Throw an entity in the direction of <paramref name="targetLoc"/> from <paramref name="sourceLoc"/>.
        /// </summary>
        /// <param name="thrownEnt">The entity to throw.</param>
        /// <param name="throwForce">
        /// The force to throw the entity with.
        /// Total impulse applied is equal to this force applied for one second.
        /// </param>
        /// <param name="targetLoc">
        /// The target location to throw at.
        /// This is only used to calculate a direction,
        /// actual distance is purely determined by <paramref name="throwForce"/>.
        /// </param>
        /// <param name="sourceLoc">
        /// The position to start the throw from.
        /// </param>
        /// <param name="spread">
        /// If true, slightly spread the actual throw angle.
        /// </param>
        /// <param name="throwSourceEnt">
        /// The entity that did the throwing. An opposite impulse will be applied to this entity if passed in.
        /// </param>
        public static void Throw(IEntity thrownEnt, float throwForce, GridCoordinates targetLoc, GridCoordinates sourceLoc, bool spread = false, IEntity throwSourceEnt = null)
        {
            if (!thrownEnt.TryGetComponent(out CollidableComponent colComp))
            {
                return;
            }

            var mapManager = IoCManager.Resolve <IMapManager>();

            colComp.CanCollide = true;
            // I can now collide with player, so that i can do damage.

            if (!thrownEnt.TryGetComponent(out ThrownItemComponent projComp))
            {
                projComp = thrownEnt.AddComponent <ThrownItemComponent>();

                if (colComp.PhysicsShapes.Count == 0)
                {
                    colComp.PhysicsShapes.Add(new PhysShapeAabb());
                }

                colComp.PhysicsShapes[0].CollisionMask |= (int)(CollisionGroup.MobImpassable | CollisionGroup.Impassable);
                colComp.Status = BodyStatus.InAir;
            }
            var angle = new Angle(targetLoc.ToMapPos(mapManager) - sourceLoc.ToMapPos(mapManager));

            if (spread)
            {
                var spreadRandom = IoCManager.Resolve <IRobustRandom>();
                angle += Angle.FromDegrees(spreadRandom.NextGaussian(0, 3));
            }

            if (throwSourceEnt != null)
            {
                projComp.User = throwSourceEnt;
                projComp.IgnoreEntity(throwSourceEnt);

                throwSourceEnt.Transform.LocalRotation = angle.GetCardinalDir().ToAngle();
            }

            if (!thrownEnt.TryGetComponent(out PhysicsComponent physComp))
            {
                physComp = thrownEnt.AddComponent <PhysicsComponent>();
            }

            var timing = IoCManager.Resolve <IGameTiming>();
            var spd    = throwForce / (1f / timing.TickRate); // acceleration is applied in 1 tick instead of 1 second, scale appropriately

            physComp.SetController <ThrowController>();
            (physComp.Controller as ThrowController)?.StartThrow(angle.ToVec() * spd);

            if (throwSourceEnt != null && throwSourceEnt.TryGetComponent <PhysicsComponent>(out var physics) &&
                physics.Controller is MoverController mover)
            {
                var physicsMgr = IoCManager.Resolve <IPhysicsManager>();

                if (physicsMgr.IsWeightless(throwSourceEnt.Transform.GridPosition))
                {
                    // We don't check for surrounding entities,
                    // so you'll still get knocked around if you're hugging the station wall in zero g.
                    // I got kinda lazy is the reason why. Also it makes a bit of sense.
                    // If somebody wants they can come along and make it so magboots completely hold you still.
                    // Would be a cool incentive to use them.
                    const float ThrowFactor = 5.0f; // Break Newton's Third Law for better gameplay
                    mover.Push(-angle.ToVec(), spd * ThrowFactor / physics.Mass);
                }
            }
        }
예제 #6
0
        /// <summary>
        ///     Throw an entity in the direction of <paramref name="targetLoc"/> from <paramref name="sourceLoc"/>.
        /// </summary>
        /// <param name="thrownEnt">The entity to throw.</param>
        /// <param name="throwForce">
        /// The force to throw the entity with.
        /// Total impulse applied is equal to this force applied for one second.
        /// </param>
        /// <param name="targetLoc">
        /// The target location to throw at.
        /// This is only used to calculate a direction,
        /// actual distance is purely determined by <paramref name="throwForce"/>.
        /// </param>
        /// <param name="sourceLoc">
        /// The position to start the throw from.
        /// </param>
        /// <param name="spread">
        /// If true, slightly spread the actual throw angle.
        /// </param>
        /// <param name="throwSourceEnt">
        /// The entity that did the throwing. An opposite impulse will be applied to this entity if passed in.
        /// </param>
        public static void Throw(IEntity thrownEnt, float throwForce, GridCoordinates targetLoc, GridCoordinates sourceLoc, bool spread = false, IEntity throwSourceEnt = null)
        {
            if (!thrownEnt.TryGetComponent(out ICollidableComponent colComp))
            {
                return;
            }

            var mapManager = IoCManager.Resolve <IMapManager>();

            colComp.CanCollide = true;
            // I can now collide with player, so that i can do damage.

            if (!thrownEnt.TryGetComponent(out ThrownItemComponent projComp))
            {
                projComp = thrownEnt.AddComponent <ThrownItemComponent>();

                if (colComp.PhysicsShapes.Count == 0)
                {
                    colComp.PhysicsShapes.Add(new PhysShapeAabb());
                }

                colComp.PhysicsShapes[0].CollisionMask |= (int)CollisionGroup.ThrownItem;
                colComp.Status = BodyStatus.InAir;
            }
            var angle = new Angle(targetLoc.ToMapPos(mapManager) - sourceLoc.ToMapPos(mapManager));

            if (spread)
            {
                var spreadRandom = IoCManager.Resolve <IRobustRandom>();
                angle += Angle.FromDegrees(spreadRandom.NextGaussian(0, 3));
            }

            if (throwSourceEnt != null)
            {
                projComp.User = throwSourceEnt;
                projComp.IgnoreEntity(throwSourceEnt);

                if (ActionBlockerSystem.CanChangeDirection(throwSourceEnt))
                {
                    throwSourceEnt.Transform.LocalRotation = angle.GetCardinalDir().ToAngle();
                }
            }

            // scaling is handled elsewhere, this is just multiplying by 10 independent of timing as a fix until elsewhere values are updated
            var spd = throwForce * 10;

            projComp.StartThrow(angle.ToVec(), spd);

            if (throwSourceEnt != null &&
                throwSourceEnt.TryGetComponent <IPhysicsComponent>(out var physics) &&
                physics.TryGetController(out MoverController mover))
            {
                var physicsMgr = IoCManager.Resolve <IPhysicsManager>();

                if (physicsMgr.IsWeightless(throwSourceEnt.Transform.GridPosition))
                {
                    // We don't check for surrounding entities,
                    // so you'll still get knocked around if you're hugging the station wall in zero g.
                    // I got kinda lazy is the reason why. Also it makes a bit of sense.
                    // If somebody wants they can come along and make it so magboots completely hold you still.
                    // Would be a cool incentive to use them.
                    const float ThrowFactor = 5.0f; // Break Newton's Third Law for better gameplay
                    mover.Push(-angle.ToVec(), spd * ThrowFactor / physics.Mass);
                }
            }
        }
예제 #7
0
        private void UserInteraction(IEntity player, GridCoordinates coordinates, EntityUid clickedUid)
        {
            // Get entity clicked upon from UID if valid UID, if not assume no entity clicked upon and null
            if (!EntityManager.TryGetEntity(clickedUid, out var attacked))
            {
                attacked = null;
            }

            // Verify player has a transform component
            if (!player.TryGetComponent <ITransformComponent>(out var playerTransform))
            {
                return;
            }

            // Verify player is on the same map as the entity he clicked on
            if (_mapManager.GetGrid(coordinates.GridID).ParentMapId != playerTransform.MapID)
            {
                Logger.WarningS("system.interaction",
                                $"Player named {player.Name} clicked on a map he isn't located on");
                return;
            }

            // Verify player has a hand, and find what object he is currently holding in his active hand
            if (!player.TryGetComponent <IHandsComponent>(out var hands))
            {
                return;
            }

            var item = hands.GetActiveHand?.Owner;

            if (!ActionBlockerSystem.CanInteract(player))
            {
                return;
            }

            playerTransform.LocalRotation = new Angle(coordinates.ToMapPos(_mapManager) - playerTransform.MapPosition.Position);

            // TODO: Check if client should be able to see that object to click on it in the first place

            // Clicked on empty space behavior, try using ranged attack
            if (attacked == null)
            {
                if (item != null)
                {
                    // After attack: Check if we clicked on an empty location, if so the only interaction we can do is AfterAttack
                    InteractAfterAttack(player, item, coordinates);
                }

                return;
            }

            // Verify attacked object is on the map if we managed to click on it somehow
            if (!attacked.Transform.IsMapTransform)
            {
                Logger.WarningS("system.interaction",
                                $"Player named {player.Name} clicked on object {attacked.Name} that isn't currently on the map somehow");
                return;
            }

            // Check if ClickLocation is in object bounds here, if not lets log as warning and see why
            if (attacked.TryGetComponent(out ICollidableComponent collideComp))
            {
                if (!collideComp.WorldAABB.Contains(coordinates.ToMapPos(_mapManager)))
                {
                    Logger.WarningS("system.interaction",
                                    $"Player {player.Name} clicked {attacked.Name} outside of its bounding box component somehow");
                    return;
                }
            }

            // RangedAttack/AfterAttack: Check distance between user and clicked item, if too large parse it in the ranged function
            // TODO: have range based upon the item being used? or base it upon some variables of the player himself?
            var distance = (playerTransform.WorldPosition - attacked.Transform.WorldPosition).LengthSquared;

            if (distance > InteractionRangeSquared)
            {
                if (item != null)
                {
                    RangedInteraction(player, item, attacked, coordinates);
                    return;
                }

                return; // Add some form of ranged AttackHand here if you need it someday, or perhaps just ways to modify the range of AttackHand
            }

            // We are close to the nearby object and the object isn't contained in our active hand
            // AttackBy/AfterAttack: We will either use the item on the nearby object
            if (item != null)
            {
                Interaction(player, item, attacked, coordinates);
            }
            // AttackHand/Activate: Since our hand is empty we will use AttackHand/Activate
            else
            {
                Interaction(player, attacked);
            }
        }
예제 #8
0
            public void Update(float frameTime)
            {
                Age += TimeSpan.FromSeconds(frameTime);
                if (Age >= Deathtime)
                {
                    return;
                }

                Velocity           += Acceleration * frameTime;
                RadialVelocity     += RadialAcceleration * frameTime;
                TangentialVelocity += TangentialAcceleration * frameTime;

                var deltaPosition = new Vector2(0f, 0f);

                //If we have an emitter we can do special effects around that emitter position
                if (_mapManager.GridExists(EmitterCoordinates.GridID))
                {
                    //Calculate delta p due to radial velocity
                    var positionRelativeToEmitter =
                        Coordinates.ToMapPos(_mapManager) - EmitterCoordinates.ToMapPos(_mapManager);
                    var deltaRadial = RadialVelocity * frameTime;
                    deltaPosition = positionRelativeToEmitter * (deltaRadial / positionRelativeToEmitter.Length);

                    //Calculate delta p due to tangential velocity
                    var radius = positionRelativeToEmitter.Length;
                    if (radius > 0)
                    {
                        var theta = (float)Math.Atan2(positionRelativeToEmitter.Y, positionRelativeToEmitter.X);
                        theta         += TangentialVelocity * frameTime;
                        deltaPosition += new Vector2(radius * (float)Math.Cos(theta), radius * (float)Math.Sin(theta))
                                         - positionRelativeToEmitter;
                    }
                }

                //Calculate new position from our velocity as well as possible rotation/movement around emitter
                deltaPosition += Velocity * frameTime;
                Coordinates    = new GridCoordinates(Coordinates.Position + deltaPosition, Coordinates.GridID);

                //Finish calculating new rotation, size, color
                Rotation += RotationRate * frameTime;
                Size     += SizeDelta * frameTime;
                Color    += ColorDelta * frameTime;

                if (RsiState == null)
                {
                    return;
                }

                // Calculate RSI animations.
                var delayCount = RsiState.DelayCount;

                if (delayCount > 0 && (AnimationLoops || AnimationIndex < delayCount - 1))
                {
                    AnimationTime += frameTime;
                    while (RsiState.GetDelay(AnimationIndex) < AnimationTime)
                    {
                        var delay = RsiState.GetDelay(AnimationIndex);
                        AnimationIndex += 1;
                        AnimationTime  -= delay;
                        if (AnimationIndex == delayCount)
                        {
                            if (AnimationLoops)
                            {
                                AnimationIndex = 0;
                            }
                            else
                            {
                                break;
                            }
                        }

                        EffectSprite = RsiState.GetFrame(RSI.State.Direction.South, AnimationIndex);
                    }
                }
            }
예제 #9
0
        public bool TryPoint(ICommonSession?session, GridCoordinates coords, EntityUid uid)
        {
            var player = session?.AttachedEntity;

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

            if (_pointers.TryGetValue(session !, out var lastTime) &&
                _gameTiming.CurTime < lastTime + PointDelay)
            {
                return(false);
            }

            if (!InRange(coords, player.Transform.GridPosition))
            {
                player.PopupMessage(player, Loc.GetString("You can't reach there!"));
                return(false);
            }

            if (ActionBlockerSystem.CanChangeDirection(player))
            {
                var diff = coords.ToMapPos(_mapManager) - player.Transform.MapPosition.Position;
                if (diff.LengthSquared > 0.01f)
                {
                    player.Transform.LocalRotation = new Angle(diff);
                }
            }

            var viewers = _playerManager.GetPlayersInRange(player.Transform.GridPosition, 15);

            EntityManager.SpawnEntity("pointingarrow", coords);

            string selfMessage;
            string viewerMessage;
            string?viewerPointedAtMessage = null;

            if (EntityManager.TryGetEntity(uid, out var pointed))
            {
                selfMessage = player == pointed
                    ? Loc.GetString("You point at yourself.")
                    : Loc.GetString("You point at {0:theName}.", pointed);

                viewerMessage = player == pointed
                    ? $"{player.Name} {Loc.GetString("points at {0:themself}.", player)}"
                    : $"{player.Name} {Loc.GetString("points at {0:theName}.", pointed)}";

                viewerPointedAtMessage = $"{player.Name} {Loc.GetString("points at you.")}";
            }
            else
            {
                var tileRef = _mapManager.GetGrid(coords.GridID).GetTileRef(coords);
                var tileDef = _tileDefinitionManager[tileRef.Tile.TypeId];

                selfMessage = Loc.GetString("You point at {0}.", tileDef.DisplayName);

                viewerMessage = $"{player.Name} {Loc.GetString("points at {0}.", tileDef.DisplayName)}";
            }

            _pointers[session !] = _gameTiming.CurTime;
예제 #10
0
        void TryStartStructureConstruction(GridCoordinates loc, string prototypeName, Angle angle, int ack)
        {
            var prototype = _prototypeManager.Index <ConstructionPrototype>(prototypeName);

            if (!InteractionChecks.InRangeUnobstructed(Owner, loc.ToMapPos(_mapManager),
                                                       ignoredEnt: Owner, insideBlockerValid: prototype.CanBuildInImpassable))
            {
                return;
            }


            if (prototype.Stages.Count < 2)
            {
                throw new InvalidOperationException($"Prototype '{prototypeName}' does not have enough stages.");
            }

            var stage0 = prototype.Stages[0];

            if (!(stage0.Forward is ConstructionStepMaterial matStep))
            {
                throw new NotImplementedException();
            }

            // Try to find the stack with the material in the user's hand.
            var hands      = Owner.GetComponent <HandsComponent>();
            var activeHand = hands.GetActiveHand?.Owner;

            if (activeHand == null)
            {
                return;
            }

            if (!activeHand.TryGetComponent(out StackComponent stack) || !ConstructionComponent.MaterialStackValidFor(matStep, stack))
            {
                return;
            }

            if (!stack.Use(matStep.Amount))
            {
                return;
            }

            // OK WE'RE GOOD CONSTRUCTION STARTED.
            _entitySystemManager.GetEntitySystem <AudioSystem>().Play("/Audio/items/deconstruct.ogg", loc);
            if (prototype.Stages.Count == 2)
            {
                // Exactly 2 stages, so don't make an intermediate frame.
                var ent = _serverEntityManager.SpawnEntity(prototype.Result, loc);
                ent.Transform.LocalRotation = angle;
            }
            else
            {
                var frame        = _serverEntityManager.SpawnEntity("structureconstructionframe", loc);
                var construction = frame.GetComponent <ConstructionComponent>();
                construction.Init(prototype);
                frame.Transform.LocalRotation = angle;
            }

            var msg = new AckStructureConstructionMessage(ack);

            SendNetworkMessage(msg);
        }
예제 #11
0
        public bool TryPoint(ICommonSession?session, GridCoordinates coords, EntityUid uid)
        {
            var player = (session as IPlayerSession)?.ContentData()?.Mind?.CurrentEntity;

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

            if (_pointers.TryGetValue(session !, out var lastTime) &&
                _gameTiming.CurTime < lastTime + PointDelay)
            {
                return(false);
            }

            if (EntityManager.TryGetEntity(uid, out var entity) && entity.HasComponent <PointingArrowComponent>())
            {
                // this is a pointing arrow. no pointing here...
                return(false);
            }

            if (!InRange(coords, player.Transform.GridPosition))
            {
                player.PopupMessage(Loc.GetString("You can't reach there!"));
                return(false);
            }

            if (ActionBlockerSystem.CanChangeDirection(player))
            {
                var diff = coords.ToMapPos(_mapManager) - player.Transform.MapPosition.Position;
                if (diff.LengthSquared > 0.01f)
                {
                    player.Transform.LocalRotation = new Angle(diff);
                }
            }

            var arrow = EntityManager.SpawnEntity("pointingarrow", coords);

            var layer = (int)VisibilityFlags.Normal;

            if (player.TryGetComponent(out VisibilityComponent? playerVisibility))
            {
                var arrowVisibility = arrow.EnsureComponent <VisibilityComponent>();
                layer = arrowVisibility.Layer = playerVisibility.Layer;
            }

            // Get players that are in range and whose visibility layer matches the arrow's.
            var viewers = _playerManager.GetPlayersBy((playerSession) =>
            {
                if ((playerSession.VisibilityMask & layer) == 0)
                {
                    return(false);
                }

                var ent = playerSession.ContentData()?.Mind?.CurrentEntity;

                return(ent != null &&
                       ent.Transform.MapPosition.InRange(player.Transform.MapPosition, PointingRange));
            });

            string selfMessage;
            string viewerMessage;
            string?viewerPointedAtMessage = null;

            if (EntityManager.TryGetEntity(uid, out var pointed))
            {
                selfMessage = player == pointed
                    ? Loc.GetString("You point at yourself.")
                    : Loc.GetString("You point at {0:theName}.", pointed);

                viewerMessage = player == pointed
                    ? $"{player.Name} {Loc.GetString("points at {0:themself}.", player)}"
                    : $"{player.Name} {Loc.GetString("points at {0:theName}.", pointed)}";

                viewerPointedAtMessage = $"{player.Name} {Loc.GetString("points at you.")}";
            }
            else
            {
                var tileRef = _mapManager.GetGrid(coords.GridID).GetTileRef(coords);
                var tileDef = _tileDefinitionManager[tileRef.Tile.TypeId];

                selfMessage = Loc.GetString("You point at {0}.", tileDef.DisplayName);

                viewerMessage = $"{player.Name} {Loc.GetString("points at {0}.", tileDef.DisplayName)}";
            }

            _pointers[session !] = _gameTiming.CurTime;
예제 #12
0
        public static void SpawnExplosion(GridCoordinates coords, int devastationRange, int heavyImpactRange, int lightImpactRange, int flashRange)
        {
            var tileDefinitionManager = IoCManager.Resolve <ITileDefinitionManager>();
            var serverEntityManager   = IoCManager.Resolve <IServerEntityManager>();
            var entitySystemManager   = IoCManager.Resolve <IEntitySystemManager>();
            var mapManager            = IoCManager.Resolve <IMapManager>();
            var robustRandom          = IoCManager.Resolve <IRobustRandom>();

            var maxRange = MathHelper.Max(devastationRange, heavyImpactRange, lightImpactRange, 0f);
            //Entity damage calculation
            var entitiesAll = serverEntityManager.GetEntitiesInRange(coords, maxRange).ToList();

            foreach (var entity in entitiesAll)
            {
                if (entity.Deleted)
                {
                    continue;
                }
                if (!entity.Transform.IsMapTransform)
                {
                    continue;
                }

                var distanceFromEntity = (int)entity.Transform.GridPosition.Distance(mapManager, coords);
                var exAct    = entitySystemManager.GetEntitySystem <ActSystem>();
                var severity = ExplosionSeverity.Destruction;
                if (distanceFromEntity < devastationRange)
                {
                    severity = ExplosionSeverity.Destruction;
                }
                else if (distanceFromEntity < heavyImpactRange)
                {
                    severity = ExplosionSeverity.Heavy;
                }
                else if (distanceFromEntity < lightImpactRange)
                {
                    severity = ExplosionSeverity.Light;
                }
                else
                {
                    continue;
                }
                //exAct.HandleExplosion(Owner, entity, severity);
                exAct.HandleExplosion(null, entity, severity);
            }

            //Tile damage calculation mockup
            //TODO: make it into some sort of actual damage component or whatever the boys think is appropriate
            var mapGrid = mapManager.GetGrid(coords.GridID);
            var circle  = new Circle(coords.Position, maxRange);
            var tiles   = mapGrid.GetTilesIntersecting(circle);

            foreach (var tile in tiles)
            {
                var tileLoc          = mapGrid.GridTileToLocal(tile.GridIndices);
                var tileDef          = (ContentTileDefinition)tileDefinitionManager[tile.Tile.TypeId];
                var distanceFromTile = (int)tileLoc.Distance(mapManager, coords);
                if (!string.IsNullOrWhiteSpace(tileDef.SubFloor))
                {
                    if (distanceFromTile < devastationRange)
                    {
                        mapGrid.SetTile(tileLoc, new Tile(tileDefinitionManager["space"].TileId));
                    }
                    if (distanceFromTile < heavyImpactRange)
                    {
                        if (robustRandom.Prob(80))
                        {
                            mapGrid.SetTile(tileLoc, new Tile(tileDefinitionManager[tileDef.SubFloor].TileId));
                        }
                        else
                        {
                            mapGrid.SetTile(tileLoc, new Tile(tileDefinitionManager["space"].TileId));
                        }
                    }
                    if (distanceFromTile < lightImpactRange)
                    {
                        if (robustRandom.Prob(50))
                        {
                            mapGrid.SetTile(tileLoc, new Tile(tileDefinitionManager[tileDef.SubFloor].TileId));
                        }
                    }
                }
            }

            //Effects and sounds
            var time    = IoCManager.Resolve <IGameTiming>().CurTime;
            var message = new EffectSystemMessage
            {
                EffectSprite = "Effects/explosion.rsi",
                RsiState     = "explosionfast",
                Born         = time,
                DeathTime    = time + TimeSpan.FromSeconds(5),
                Size         = new Vector2(flashRange / 2, flashRange / 2),
                Coordinates  = coords,
                //Rotated from east facing
                Rotation   = 0f,
                ColorDelta = new Vector4(0, 0, 0, -1500f),
                Color      = Vector4.Multiply(new Vector4(255, 255, 255, 750), 0.5f),
                Shaded     = false
            };

            entitySystemManager.GetEntitySystem <EffectSystem>().CreateParticle(message);
            entitySystemManager.GetEntitySystem <AudioSystem>().Play("/Audio/effects/explosion.ogg", coords);

            // Knock back cameras of all players in the area.

            var playerManager = IoCManager.Resolve <IPlayerManager>();

            foreach (var player in playerManager.GetAllPlayers())
            {
                if (player.AttachedEntity == null ||
                    player.AttachedEntity.Transform.MapID != mapGrid.ParentMapId ||
                    !player.AttachedEntity.TryGetComponent(out CameraRecoilComponent recoil))
                {
                    continue;
                }

                var playerPos = player.AttachedEntity.Transform.WorldPosition;
                var delta     = coords.ToMapPos(mapManager) - playerPos;
                var distance  = delta.LengthSquared;

                var effect = 1 / (1 + 0.2f * distance);
                if (effect > 0.01f)
                {
                    var kick = -delta.Normalized * effect;
                    recoil.Kick(kick);
                }
            }
        }