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