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);
}
}
}
}