using Content.Server.Explosion.EntitySystems; using Content.Shared.Damage; // DeltaV - EMP damage 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; using Content.Shared._NF.Emp.Components; // Frontier using Robust.Server.GameStates; // Frontier: EMP Blast PVS using Robust.Shared.Configuration; // Frontier: EMP Blast PVS using Robust.Shared; // Frontier: EMP Blast PVS namespace Content.Server.Emp; public sealed class EmpSystem : SharedEmpSystem { [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly TransformSystem _transform = default!; [Dependency] private readonly PvsOverrideSystem _pvs = default!; // Frontier: EMP Blast PVS [Dependency] private readonly IConfigurationManager _cfg = default!; // Frontier: EMP Blast PVS public const string EmpPulseEffectPrototype = "EffectEmpBlast"; // Frontier: EffectEmpPulse public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnExamine); SubscribeLocalEvent(OnRadioSendAttempt); SubscribeLocalEvent(OnRadioReceiveAttempt); SubscribeLocalEvent(OnApcToggleMainBreaker); SubscribeLocalEvent(OnCameraSetActive); } /// /// DeltaV - Triggers an EMP pulse at the given location, by first raising an , then a raising on all entities in range. /// Shim for Upstream EmpPulse method. /// /// 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 override void EmpPulse(MapCoordinates coordinates, float range, float energyConsumption, float duration) { this.EmpPulse(coordinates, range, energyConsumption, duration, null); } /// /// 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. /// DeltaV - the damage dealt by the EMP to silicons instead of draining their power cells. public void EmpPulse(MapCoordinates coordinates, float range, float energyConsumption, float duration, DamageSpecifier? damage = null) { // TODO: AUM - Slightly refactor this if (damage == null) damage = new() { DamageDict = new() { { "Ion", 80 } } }; // DeltaV - EMP damage foreach (var uid in _lookup.GetEntitiesInRange(coordinates, range)) { TryEmpEffects(uid, energyConsumption, duration, damage); } var empBlast = Spawn(EmpPulseEffectPrototype, coordinates); // Frontier: Added visual effect EnsureComp(empBlast, out var empBlastComp); // Frontier empBlastComp.VisualRange = range; // Frontier if (range > _cfg.GetCVar(CVars.NetMaxUpdateRange)) // Frontier _pvs.AddGlobalOverride(empBlast); // Frontier Dirty(empBlast, empBlastComp); // Frontier } /// /// 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. /// DeltaV - the damage dealt by the EMP to silicons instead of draining their power cells. public void TryEmpEffects(EntityUid uid, float energyConsumption, float duration, DamageSpecifier? damage = null) { var attemptEv = new EmpAttemptEvent(); RaiseLocalEvent(uid, attemptEv); if (attemptEv.Cancelled) return; DoEmpEffects(uid, energyConsumption, duration, damage); // DeltaV - EMP damage } /// /// 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. /// DeltaV - the damage dealt by the EMP to silicons instead of draining their power cells. public void DoEmpEffects(EntityUid uid, float energyConsumption, float duration, DamageSpecifier? damage = null) { if (damage == null) damage = new() { DamageDict = new() { { "Ion", 80 } } }; // DeltaV - EMP damage 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")); } /* Removed in Trigger Refactor private void HandleEmpTrigger(EntityUid uid, EmpOnTriggerComponent comp, TriggerEvent args) { EmpPulse(_transform.GetMapCoordinates(uid), comp.Range, comp.EnergyConsumption, comp.DisableDuration, comp.Damage); // DeltaV - EMP damage 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(DamageSpecifier? damage = null) : CancellableEntityEventArgs // DeltaV - EMP damage { public DamageSpecifier? Damage = (damage == null) ? new() { DamageDict = new() { {"Ion", 80 } } } : damage; // DeltaV - EMP damage; } [ByRefEvent] public record struct EmpPulseEvent(float EnergyConsumption, bool Affected, bool Disabled, TimeSpan Duration); [ByRefEvent] public record struct EmpDisabledRemoved();