using Content.Server.Power.EntitySystems; using Content.Server.Radio; using Content.Server.SurveillanceCamera; using Content.Shared.Emp; using Robust.Shared.Map; namespace Content.Server.Emp; public sealed class EmpSystem : SharedEmpSystem { [Dependency] private readonly EntityLookupSystem _lookup = default!; public const string EmpPulseEffectPrototype = "EffectEmpPulse"; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnRadioSendAttempt); SubscribeLocalEvent(OnRadioReceiveAttempt); SubscribeLocalEvent(OnApcToggleMainBreaker); SubscribeLocalEvent(OnCameraSetActive); } public override void EmpPulse(MapCoordinates coordinates, float range, float energyConsumption, float duration) { foreach (var uid in _lookup.GetEntitiesInRange(coordinates, range)) { TryEmpEffects(uid, energyConsumption, duration); } Spawn(EmpPulseEffectPrototype, coordinates); } /// /// 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. public void EmpPulse(EntityCoordinates coordinates, float range, float energyConsumption, float duration) { foreach (var uid in _lookup.GetEntitiesInRange(coordinates, range)) { TryEmpEffects(uid, energyConsumption, duration); } Spawn(EmpPulseEffectPrototype, coordinates); } /// /// Attempts to apply the effects of an EMP pulse onto an entity by first raising an , followed by raising a on it. /// /// The entity to apply the EMP effects on. /// The amount of energy consumed by the EMP. /// The duration of the EMP effects. public void TryEmpEffects(EntityUid uid, float energyConsumption, float duration) { var attemptEv = new EmpAttemptEvent(); RaiseLocalEvent(uid, attemptEv); if (attemptEv.Cancelled) return; DoEmpEffects(uid, energyConsumption, duration); } /// /// Applies the effects of an EMP pulse onto an entity by raising a on it. /// /// The entity to apply the EMP effects on. /// The amount of energy consumed by the EMP. /// The duration of the EMP effects. public void DoEmpEffects(EntityUid uid, float energyConsumption, float duration) { var ev = new EmpPulseEvent(energyConsumption, false, false, TimeSpan.FromSeconds(duration)); RaiseLocalEvent(uid, ref ev); if (ev.Affected) Spawn(EmpDisabledEffectPrototype, Transform(uid).Coordinates); if (!ev.Disabled) return; var disabled = EnsureComp(uid); disabled.DisabledUntil = Timing.CurTime + TimeSpan.FromSeconds(duration); } public override void Update(float frameTime) { base.Update(frameTime); var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var comp)) { if (comp.DisabledUntil < Timing.CurTime) { RemComp(uid); var ev = new EmpDisabledRemoved(); RaiseLocalEvent(uid, ref ev); } } } private void OnRadioSendAttempt(EntityUid uid, EmpDisabledComponent component, ref RadioSendAttemptEvent args) { args.Cancelled = true; } private void OnRadioReceiveAttempt(EntityUid uid, EmpDisabledComponent component, ref RadioReceiveAttemptEvent args) { args.Cancelled = true; } private void OnApcToggleMainBreaker(EntityUid uid, EmpDisabledComponent component, ref ApcToggleMainBreakerAttemptEvent args) { args.Cancelled = true; } private void OnCameraSetActive(EntityUid uid, EmpDisabledComponent component, ref SurveillanceCameraSetActiveAttemptEvent args) { args.Cancelled = true; } } /// /// Raised on an entity before . Cancel this to prevent the emp event being raised. /// public sealed partial class EmpAttemptEvent : CancellableEntityEventArgs; [ByRefEvent] public record struct EmpPulseEvent(float EnergyConsumption, bool Affected, bool Disabled, TimeSpan Duration); [ByRefEvent] public record struct EmpDisabledRemoved();