--- /dev/null
+namespace Content.Server.Emp;
+
+/// <summary>
+/// Upon being triggered will EMP area around it.
+/// </summary>
+[RegisterComponent]
+sealed class EmpOnTriggerComponent : Component
+{
+ [DataField("range"), ViewVariables(VVAccess.ReadWrite)]
+ public float Range = 1.0f;
+
+ /// <summary>
+ /// How much energy will be consumed per battery in range
+ /// </summary>
+ [DataField("energyConsumption"), ViewVariables(VVAccess.ReadWrite)]
+ public float EnergyConsumption;
+}
--- /dev/null
+using Content.Server.Explosion.EntitySystems;
+using Robust.Shared.Map;
+
+namespace Content.Server.Emp;
+
+public sealed class EmpSystem : EntitySystem
+{
+ [Dependency] private readonly EntityLookupSystem _lookup = default!;
+
+ public const string EmpPulseEffectPrototype = "EffectEmpPulse";
+ public const string EmpDisabledEffectPrototype = "EffectEmpDisabled";
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent<EmpOnTriggerComponent, TriggerEvent>(HandleEmpTrigger);
+ }
+
+ public void EmpPulse(MapCoordinates coordinates, float range, float energyConsumption)
+ {
+ foreach (var uid in _lookup.GetEntitiesInRange(coordinates, range))
+ {
+ var ev = new EmpPulseEvent(energyConsumption, false);
+ RaiseLocalEvent(uid, ref ev);
+ if (ev.Affected)
+ Spawn(EmpDisabledEffectPrototype, Transform(uid).Coordinates);
+ }
+ Spawn(EmpPulseEffectPrototype, coordinates);
+ }
+
+ private void HandleEmpTrigger(EntityUid uid, EmpOnTriggerComponent comp, TriggerEvent args)
+ {
+ EmpPulse(Transform(uid).Coordinates.ToMap(EntityManager), comp.Range, comp.EnergyConsumption);
+ args.Handled = true;
+ }
+}
+
+[ByRefEvent]
+public record struct EmpPulseEvent(float EnergyConsumption, bool Affected);
using Robust.Shared.Player;
using Robust.Shared.Timing;
using Content.Shared.DoAfter;
+using Content.Server.Emp;
namespace Content.Server.Light.EntitySystems
{
SubscribeLocalEvent<PoweredLightComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<PoweredLightComponent, DoAfterEvent>(OnDoAfter);
+
+ SubscribeLocalEvent<PoweredLightComponent, EmpPulseEvent>(OnEmpPulse);
}
private void OnInit(EntityUid uid, PoweredLightComponent light, ComponentInit args)
args.Handled = true;
}
+
+ private void OnEmpPulse(EntityUid uid, PoweredLightComponent component, ref EmpPulseEvent args)
+ {
+ args.Affected = true;
+ TryDestroyBulb(uid, component);
+ }
}
}
+using Content.Server.Emp;
using Content.Server.Popups;
using Content.Server.Power.Components;
using Content.Shared.Access.Components;
SubscribeLocalEvent<ApcToolFinishedEvent>(OnToolFinished);
SubscribeLocalEvent<ApcComponent, InteractUsingEvent>(OnInteractUsing);
SubscribeLocalEvent<ApcComponent, ExaminedEvent>(OnExamine);
+
+ SubscribeLocalEvent<ApcComponent, EmpPulseEvent>(OnEmpPulse);
}
// Change the APC's state only when the battery state changes, or when it's first created.
? "apc-component-on-examine-panel-open"
: "apc-component-on-examine-panel-closed"));
}
+
+ private void OnEmpPulse(EntityUid uid, ApcComponent component, ref EmpPulseEvent args)
+ {
+ if (component.MainBreakerEnabled)
+ {
+ args.Affected = true;
+ ApcToggleBreaker(uid, component);
+ }
+ }
}
}
using Content.Server.Cargo.Systems;
+using Content.Server.Emp;
using Content.Server.Power.Components;
using Content.Shared.Examine;
using Content.Shared.Rejuvenate;
SubscribeLocalEvent<PowerNetworkBatteryComponent, RejuvenateEvent>(OnNetBatteryRejuvenate);
SubscribeLocalEvent<BatteryComponent, RejuvenateEvent>(OnBatteryRejuvenate);
SubscribeLocalEvent<BatteryComponent, PriceCalculationEvent>(CalculateBatteryPrice);
+ SubscribeLocalEvent<BatteryComponent, EmpPulseEvent>(OnEmpPulse);
SubscribeLocalEvent<NetworkBatteryPreSync>(PreSync);
SubscribeLocalEvent<NetworkBatteryPostSync>(PostSync);
{
args.Price += component.CurrentCharge * component.PricePerJoule;
}
+
+ private void OnEmpPulse(EntityUid uid, BatteryComponent component, ref EmpPulseEvent args)
+ {
+ args.Affected = true;
+ component.UseCharge(args.EnergyConsumption);
+ }
}
}
uplink-c4-bundle-name = C-4 bundle
uplink-c4-bundle-desc = Because sometimes quantity is quality. Contains 8 C-4 plastic explosives.
+uplink-emp-grenade-name = Emp Grenade
+uplink-emp-grenade-desc = Releases electromagnetic pulses that disrupt or damage many electronic devices or drain power cells.
+
# Ammo
uplink-pistol-magazine-name = Pistol Magazine (.35 auto)
uplink-pistol-magazine-desc = Pistol magazine with 10 catridges. Compatible with Viper.
categories:
- UplinkExplosives
+- type: listing
+ id: UplinkEmpGrenade
+ name: uplink-emp-grenade-name
+ description: uplink-emp-grenade-desc
+ productEntity: EmpGrenade
+ cost:
+ Telecrystal: 4
+ categories:
+ - UplinkExplosives
+
# Ammo
- type: listing
--- /dev/null
+- type: entity
+ id: EffectEmpPulse
+ noSpawn: true
+ components:
+ - type: TimedDespawn
+ lifetime: 0.8
+ - type: Sprite
+ netsync: false
+ drawdepth: Effects
+ noRot: true
+ layers:
+ - shader: unshaded
+ map: ["enum.EffectLayers.Unshaded"]
+ sprite: Effects/emp.rsi
+ state: emp_pulse
+ - type: EffectVisuals
+ - type: Tag
+ tags:
+ - HideContextMenu
+ - type: EmitSoundOnSpawn
+ sound:
+ path: /Audio/Effects/Lightning/lightningbolt.ogg
+ - type: AnimationPlayer
+
+- type: entity
+ id: EffectEmpDisabled
+ noSpawn: true
+ components:
+ - type: TimedDespawn
+ lifetime: 0.4
+ - type: Sprite
+ netsync: false
+ drawdepth: Effects
+ noRot: true
+ layers:
+ - shader: unshaded
+ map: ["enum.EffectLayers.Unshaded"]
+ sprite: Effects/emp.rsi
+ state: emp_disable
+ - type: EffectVisuals
+ - type: Tag
+ tags:
+ - HideContextMenu
+ - type: AnimationPlayer
enum.Trigger.TriggerVisualState.Unprimed: complete
- type: StaticPrice
price: 25
+
+- type: entity
+ name: emp grenade
+ description: Releases electromagnetic pulses that disrupt or damage many electronic devices or drain power cells.
+ parent: GrenadeBase
+ id: EmpGrenade
+ components:
+ - type: Sprite
+ sprite: Objects/Weapons/Grenades/empgrenade.rsi
+ - type: EmpOnTrigger
+ range: 4
+ energyConsumption: 50000
+ - type: DeleteOnTrigger
+ - type: Appearance
+ visuals:
+ - type: TimerTriggerVisualizer
+ countdown_sound:
+ path: /Audio/Effects/countdown.ogg
--- /dev/null
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/e52683d3872347af447bb0ff74c420d4a4e91ea8",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "emp_disable",
+ "directions": 4,
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ],
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "emp_pulse",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/e52683d3872347af447bb0ff74c420d4a4e91ea8",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "icon"
+ },
+ {
+ "name": "primed",
+ "delays": [
+ [
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "equipped-BELT",
+ "directions": 4
+ }
+ ]
+}