using System.Collections.Generic; using Content.Server.Camera; using Content.Shared.Gravity; using Robust.Server.Player; using Robust.Shared.Audio; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Player; using Robust.Shared.Random; namespace Content.Server.Gravity.EntitySystems { /// /// Handles the grid shake effect used by the gravity generator. /// public sealed class GravityShakeSystem : EntitySystem { [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IRobustRandom _random = default!; private Dictionary _gridsToShake = new(); private const float GravityKick = 100.0f; private const uint ShakeTimes = 10; private float _internalTimer = 0.0f; public override void Update(float frameTime) { if (_gridsToShake.Count > 0) { _internalTimer += frameTime; if (_internalTimer > 0.2f) { // TODO: Could just have clients do this themselves via event and save bandwidth. ShakeGrids(); _internalTimer -= 0.2f; } } else { _internalTimer = 0.0f; } } public void ShakeGrid(GridId gridId, GravityComponent comp) { _gridsToShake[gridId] = ShakeTimes; SoundSystem.Play( Filter.BroadcastGrid(gridId), comp.GravityShakeSound.GetSound(), AudioParams.Default.WithVolume(-2f)); } private void ShakeGrids() { // I have to copy this because C# doesn't allow changing collections while they're // getting enumerated. var gridsToShake = new Dictionary(_gridsToShake); foreach (var gridId in _gridsToShake.Keys) { if (_gridsToShake[gridId] == 0) { gridsToShake.Remove(gridId); continue; } ShakeGrid(gridId); gridsToShake[gridId] -= 1; } _gridsToShake = gridsToShake; } private void ShakeGrid(GridId gridId) { foreach (var player in _playerManager.GetAllPlayers()) { if (player.AttachedEntity == null || player.AttachedEntity.Transform.GridID != gridId || !player.AttachedEntity.TryGetComponent(out CameraRecoilComponent? recoil)) { continue; } recoil.Kick(new Vector2(_random.NextFloat(), _random.NextFloat()) * GravityKick); } } } }