using Content.Server.Explosion.EntitySystems; using Content.Server.Power.EntitySystems; using Content.Server.Radio; using Content.Server.SurveillanceCamera; using Content.Shared.Emp; using Content.Shared.Examine; using Robust.Server.GameObjects; using Robust.Shared.Map; namespace Content.Server.Emp; public sealed class EmpSystem : SharedEmpSystem { [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly TransformSystem _transform = default!; public const string EmpPulseEffectPrototype = "EffectEmpPulse"; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnExamine); SubscribeLocalEvent(HandleEmpTrigger); SubscribeLocalEvent(OnRadioSendAttempt); SubscribeLocalEvent(OnRadioReceiveAttempt); SubscribeLocalEvent(OnApcToggleMainBreaker); SubscribeLocalEvent(OnCameraSetActive); } /// /// 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(MapCoordinates 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) { 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 OnExamine(EntityUid uid, EmpDisabledComponent component, ExaminedEvent args) { args.PushMarkup(Loc.GetString("emp-disabled-comp-on-examine")); } private void HandleEmpTrigger(EntityUid uid, EmpOnTriggerComponent comp, TriggerEvent args) { EmpPulse(_transform.GetMapCoordinates(uid), comp.Range, comp.EnergyConsumption, comp.DisableDuration); args.Handled = true; } 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();