using Content.Shared.Examine;
using Content.Shared.Rejuvenate;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Map;
using Robust.Shared.Timing;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Content.Shared._NF.Emp.Components;
using Robust.Shared.GameStates;
using Robust.Shared.Configuration; // Frontier
using Robust.Shared;
using Content.Shared.Damage; // Frontier
namespace Content.Shared.Emp;
public abstract class SharedEmpSystem : EntitySystem
{
[Dependency] protected readonly IGameTiming Timing = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly INetManager _net = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedPvsOverrideSystem _pvs = default!; // Frontier
[Dependency] private readonly IConfigurationManager _cfg = default!; // Frontier: EMP Blast PVS
///
/// DeltaV. Default damage of EMPs, as dertermined by direction. There's no good component to put
/// this on so its defined here.
///
private static readonly DamageSpecifier? DefaultEmpDamage = new() { DamageDict = new() { { "Ion", 130 } } };
private HashSet _entSet = new();
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent(OnExamine);
SubscribeLocalEvent(OnRemove);
SubscribeLocalEvent(OnRejuvenate);
}
public static readonly EntProtoId EmpPulseEffectPrototype = "EffectEmpBlast"; // Frontier - was EffectEmpPulse
public static readonly EntProtoId EmpDisabledEffectPrototype = "EffectEmpDisabled";
public static readonly SoundSpecifier EmpSound = new SoundPathSpecifier("/Audio/Effects/Lightning/lightningbolt.ogg");
///
/// Triggers an EMP pulse at the given location, by first raising an , then by raising on all entities in range.
///
/// The location to trigger the EMP pulse at.
/// The range of the EMP pulse.
/// The amount of energy consumed by the EMP pulse. In Joule.
/// The duration of the EMP effects.
/// The player that caused the effect. Used for predicted audio.
/// DeltaV - The damage that that EMP will do. If not specified or null, will do 130 Ion damage. To do no damage, pass in a DamageSpecifier with no damage types.
public void EmpPulse(MapCoordinates mapCoordinates, float range, float energyConsumption, TimeSpan duration, EntityUid? user = null, DamageSpecifier? damage = null) // DeltaV - Add Ion Damage
{
foreach (var uid in _lookup.GetEntitiesInRange(mapCoordinates, range))
{
TryEmpEffects(uid, energyConsumption, duration, user, damage ?? DefaultEmpDamage); // DeltaV - Add Ion Damage
}
// TODO: replace with PredictedSpawn once it works with animated sprites
if (_net.IsServer)
{
var emp = Spawn(EmpPulseEffectPrototype, mapCoordinates); // Frontier: Added visual effect
EnsureComp(emp, out var empBlast); // Frontier
empBlast.VisualRange = range; // Frontier
if (range > _cfg.GetCVar(CVars.NetMaxUpdateRange)) // Frontier
_pvs.AddGlobalOverride(emp); // Frontier
Dirty(emp, empBlast); // Frontier
}
var coordinates = _transform.ToCoordinates(mapCoordinates);
_audio.PlayPredicted(EmpSound, coordinates, user);
}
///
/// Triggers an EMP pulse at the given location, by first raising an , then a raising on all entities in range.
///
/// The location to trigger the EMP pulse at.
/// The range of the EMP pulse.
/// The amount of energy consumed by the EMP pulse.
/// The duration of the EMP effects.
/// The player that caused the effect. Used for predicted audio.'
/// DeltaV - The damage that that EMP will do. If not specified or null, will do 130 Ion damage. To do no damage, pass in a DamageSpecifier with no damage types.
public void EmpPulse(EntityCoordinates coordinates, float range, float energyConsumption, TimeSpan duration, EntityUid? user = null, DamageSpecifier? damage = null) // DeltaV - Add Ion Damage
{
_entSet.Clear();
_lookup.GetEntitiesInRange(coordinates, range, _entSet);
foreach (var uid in _entSet)
{
TryEmpEffects(uid, energyConsumption, duration, user, damage ?? DefaultEmpDamage); // DeltaV - Add Ion Damage
}
// TODO: replace with PredictedSpawn once it works with animated sprites
if (_net.IsServer)
{
var emp = Spawn(EmpPulseEffectPrototype, coordinates); // Frontier: Added visual effect
EnsureComp(emp, out var empBlast); // Frontier
empBlast.VisualRange = range; // Frontier
if (range > _cfg.GetCVar(CVars.NetMaxUpdateRange)) // Frontier
_pvs.AddGlobalOverride(emp); // Frontier
Dirty(emp, empBlast); // Frontier
}
_audio.PlayPredicted(EmpSound, coordinates, user);
}
///
/// Attempts to apply the effects of an EMP pulse onto an entity by first raising an , followed by raising a on it.
///
///
DeltaV - In most cases, you will want to use instead.
///
/// The entity to apply the EMP effects on.
/// The amount of energy consumed by the EMP.
/// The duration of the EMP effects.
/// The player that caused the EMP. For prediction purposes.
/// DeltaV - The damage that that EMP will do. If null, no damage is done.
/// If the entity was affected by the EMP.
public bool TryEmpEffects(EntityUid uid, float energyConsumption, TimeSpan duration, EntityUid? user = null, DamageSpecifier? damage = null) // DeltaV - Add Ion Damage
{
var attemptEv = new EmpAttemptEvent();
RaiseLocalEvent(uid, ref attemptEv);
if (attemptEv.Cancelled)
return false;
return DoEmpEffects(uid, energyConsumption, duration, user, damage); // DeltaV - Add Ion Damage
}
///
/// Applies the effects of an EMP pulse onto an entity by raising a on it.
///
///
DeltaV - In most cases, you will want to use instead.
///
/// The entity to apply the EMP effects on.
/// The amount of energy consumed by the EMP.
/// The duration of the EMP effects.
/// The player that caused the EMP. For prediction purposes.
/// DeltaV - The damage that that EMP will do. If null, no damage is done.
/// If the entity was affected by the EMP.
public bool DoEmpEffects(EntityUid uid, float energyConsumption, TimeSpan duration, EntityUid? user = null, DamageSpecifier? damage = null) // DeltaV - Add Ion Damage
{
var ev = new EmpPulseEvent(energyConsumption, false, false, duration, user, damage); // DeltaV - Add Ion Damage
RaiseLocalEvent(uid, ref ev);
// TODO: replace with PredictedSpawn once it works with animated sprites
if (ev.Affected && _net.IsServer)
Spawn(EmpDisabledEffectPrototype, Transform(uid).Coordinates);
if (!ev.Disabled)
return ev.Affected;
var disabled = EnsureComp(uid);
disabled.DisabledUntil = Timing.CurTime + duration;
Dirty(uid, disabled);
return ev.Affected;
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var curTime = Timing.CurTime;
var query = EntityQueryEnumerator();
while (query.MoveNext(out var uid, out var comp))
{
if (curTime < comp.DisabledUntil)
continue;
RemComp(uid);
}
}
private void OnExamine(Entity ent, ref ExaminedEvent args)
{
args.PushMarkup(Loc.GetString("emp-disabled-comp-on-examine"));
}
private void OnRemove(Entity ent, ref ComponentRemove args)
{
var ev = new EmpDisabledRemovedEvent();
RaiseLocalEvent(ent, ref ev);
}
private void OnRejuvenate(Entity ent, ref RejuvenateEvent args)
{
RemCompDeferred(ent);
}
}
///
/// Raised on an entity before . Cancel this to prevent the emp event being raised.
///
[ByRefEvent]
public record struct EmpAttemptEvent(bool Cancelled);
///
/// Raised on an entity when it gets hit by an EMP Pulse.
///
/// The amount of energy to remove from batteries. In Joule.
/// Set this is true in the subscription to spawn a visual effect at the entity's location.
/// Set this to ture in the subscription to add to the entity.
/// The duration the entity will be disabled.
/// The player that caused the EMP. For prediction purposes.
[ByRefEvent]
public record struct EmpPulseEvent(float EnergyConsumption, bool Affected, bool Disabled, TimeSpan Duration, EntityUid? User, DamageSpecifier? Damage = null); // DeltaV - Added Damage
///
/// Raised on an entity after is removed.
///
[ByRefEvent]
public record struct EmpDisabledRemovedEvent();