]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Add radio jammer (#14369)
authorSlava0135 <40753025+Slava0135@users.noreply.github.com>
Fri, 14 Apr 2023 19:50:19 +0000 (22:50 +0300)
committerGitHub <noreply@github.com>
Fri, 14 Apr 2023 19:50:19 +0000 (12:50 -0700)
12 files changed:
Content.Server/Radio/Components/ActiveRadioJammerComponent.cs [new file with mode: 0644]
Content.Server/Radio/Components/RadioJammerComponent.cs [new file with mode: 0644]
Content.Server/Radio/EntitySystems/JammerSystem.cs [new file with mode: 0644]
Content.Server/Radio/EntitySystems/RadioSystem.cs
Content.Server/Radio/RadioEvent.cs [new file with mode: 0644]
Content.Server/Radio/RadioReceiveEvent.cs [deleted file]
Resources/Locale/en-US/radio/components/radio-jammer-component.ftl [new file with mode: 0644]
Resources/Locale/en-US/store/uplink-catalog.ftl
Resources/Prototypes/Catalog/uplink_catalog.yml
Resources/Prototypes/Entities/Objects/Tools/jammer.yml [new file with mode: 0644]
Resources/Textures/Objects/Devices/jammer.rsi/jammer.png [new file with mode: 0644]
Resources/Textures/Objects/Devices/jammer.rsi/meta.json [new file with mode: 0644]

diff --git a/Content.Server/Radio/Components/ActiveRadioJammerComponent.cs b/Content.Server/Radio/Components/ActiveRadioJammerComponent.cs
new file mode 100644 (file)
index 0000000..e608f0b
--- /dev/null
@@ -0,0 +1,12 @@
+using Content.Server.Radio.EntitySystems;
+
+namespace Content.Server.Radio.Components;
+
+/// <summary>
+/// Prevents all radio in range from sending messages
+/// </summary>
+[RegisterComponent]
+[Access(typeof(JammerSystem))]
+public sealed class ActiveRadioJammerComponent : Component
+{
+}
diff --git a/Content.Server/Radio/Components/RadioJammerComponent.cs b/Content.Server/Radio/Components/RadioJammerComponent.cs
new file mode 100644 (file)
index 0000000..ef451b0
--- /dev/null
@@ -0,0 +1,20 @@
+using Content.Server.Radio.EntitySystems;
+
+namespace Content.Server.Radio.Components;
+
+/// <summary>
+/// When activated (<see cref="ActiveRadioJammerComponent"/>) prevents from sending messages in range
+/// </summary>
+[RegisterComponent]
+[Access(typeof(JammerSystem))]
+public sealed class RadioJammerComponent : Component
+{
+    [DataField("range"), ViewVariables(VVAccess.ReadWrite)]
+    public float Range = 8f;
+
+    /// <summary>
+    /// Power usage per second when enabled
+    /// </summary>
+    [DataField("wattage"), ViewVariables(VVAccess.ReadWrite)]
+    public float Wattage = 6f;
+}
diff --git a/Content.Server/Radio/EntitySystems/JammerSystem.cs b/Content.Server/Radio/EntitySystems/JammerSystem.cs
new file mode 100644 (file)
index 0000000..d3e1869
--- /dev/null
@@ -0,0 +1,91 @@
+using Content.Server.Popups;
+using Content.Server.PowerCell;
+using Content.Server.Radio.Components;
+using Content.Shared.Examine;
+using Content.Shared.Interaction;
+using Content.Shared.PowerCell.Components;
+
+namespace Content.Server.Radio.EntitySystems;
+
+public sealed class JammerSystem : EntitySystem
+{
+    [Dependency] private readonly PowerCellSystem _powerCell = default!;
+    [Dependency] private readonly PopupSystem _popup = default!;
+    [Dependency] private readonly SharedTransformSystem _transform = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<RadioJammerComponent, ActivateInWorldEvent>(OnActivate);
+        SubscribeLocalEvent<ActiveRadioJammerComponent, PowerCellChangedEvent>(OnPowerCellChanged);
+        SubscribeLocalEvent<RadioJammerComponent, ExaminedEvent>(OnExamine);
+        SubscribeLocalEvent<RadioSendAttemptEvent>(OnRadioSendAttempt);
+    }
+
+    public override void Update(float frameTime)
+    {
+        var query = AllEntityQuery<ActiveRadioJammerComponent, RadioJammerComponent>();
+        while (query.MoveNext(out var uid, out var _, out var jam))
+        {
+            if (_powerCell.TryGetBatteryFromSlot(uid, out var battery) &&
+                !battery.TryUseCharge(jam.Wattage * frameTime))
+            {
+                RemComp<ActiveRadioJammerComponent>(uid);
+            }
+        }
+    }
+
+    private void OnActivate(EntityUid uid, RadioJammerComponent comp, ActivateInWorldEvent args)
+    {
+        var activated = !HasComp<ActiveRadioJammerComponent>(uid) && 
+            _powerCell.TryGetBatteryFromSlot(uid, out var battery) &&
+            battery.CurrentCharge > comp.Wattage;
+        if (activated)
+        {
+            EnsureComp<ActiveRadioJammerComponent>(uid);
+        }
+        else
+        {
+            RemComp<ActiveRadioJammerComponent>(uid);
+        }
+        var state = Loc.GetString(activated ? "radio-jammer-component-on-state" : "radio-jammer-component-off-state");
+        var message = Loc.GetString("radio-jammer-component-on-use", ("state", state));
+        _popup.PopupEntity(message, args.User, args.User);
+        args.Handled = true;
+    }
+
+    private void OnPowerCellChanged(EntityUid uid, ActiveRadioJammerComponent comp, PowerCellChangedEvent args)
+    {
+        if (args.Ejected)
+            RemComp<ActiveRadioJammerComponent>(uid);
+    }
+
+    private void OnExamine(EntityUid uid, RadioJammerComponent comp, ExaminedEvent args)
+    {
+        if (args.IsInDetailsRange)
+        {
+            var msg = HasComp<ActiveRadioJammerComponent>(uid)
+                ? Loc.GetString("radio-jammer-component-examine-on-state")
+                : Loc.GetString("radio-jammer-component-examine-off-state");
+            args.PushMarkup(msg);
+            if (_powerCell.TryGetBatteryFromSlot(uid, out var battery))
+                args.PushMarkup(Loc.GetString("radio-jammer-component-charge",
+                    ("charge", (int) ((battery.CurrentCharge / battery.MaxCharge) * 100))));
+        }
+    }
+
+    private void OnRadioSendAttempt(ref RadioSendAttemptEvent args)
+    {
+        var source = Transform(args.RadioSource).Coordinates;
+        var query = AllEntityQuery<ActiveRadioJammerComponent, RadioJammerComponent, TransformComponent>();
+        while (query.MoveNext(out _, out _, out var jam, out var transform))
+        {
+            if (source.InRange(EntityManager, _transform, transform.Coordinates, jam.Range))
+            {
+                args.Cancelled = true;
+                return;
+            }
+        }
+    }
+}
index 6557d5edef0f7d806f83427b06c69e40729e4e69..2e6b93be3208347161554026340591cb98f77edc 100644 (file)
@@ -78,6 +78,10 @@ public sealed class RadioSystem : EntitySystem
         var chatMsg = new MsgChatMessage { Message = chat };
         var ev = new RadioReceiveEvent(message, messageSource, channel, chatMsg);
 
+        var sendAttemptEv = new RadioSendAttemptEvent(channel, radioSource);
+        RaiseLocalEvent(ref sendAttemptEv);
+        var canSend = !sendAttemptEv.Cancelled;
+
         var sourceMapId = Transform(radioSource).MapID;
         var hasActiveServer = HasActiveServer(sourceMapId, channel.ID);
         var hasMicro = HasComp<RadioMicrophoneComponent>(radioSource);
@@ -85,7 +89,7 @@ public sealed class RadioSystem : EntitySystem
         var speakerQuery = GetEntityQuery<RadioSpeakerComponent>();
         var radioQuery = AllEntityQuery<ActiveRadioComponent, TransformComponent>();
         var sentAtLeastOnce = false;
-        while (radioQuery.MoveNext(out var receiver, out var radio, out var transform))
+        while (canSend && radioQuery.MoveNext(out var receiver, out var radio, out var transform))
         {
             if (!radio.Channels.Contains(channel.ID))
                 continue;
diff --git a/Content.Server/Radio/RadioEvent.cs b/Content.Server/Radio/RadioEvent.cs
new file mode 100644 (file)
index 0000000..69d764f
--- /dev/null
@@ -0,0 +1,30 @@
+using Content.Shared.Chat;
+using Content.Shared.Radio;
+
+namespace Content.Server.Radio;
+
+[ByRefEvent]
+public readonly record struct RadioReceiveEvent(string Message, EntityUid MessageSource, RadioChannelPrototype Channel, MsgChatMessage ChatMsg);
+
+/// <summary>
+/// Use this event to cancel sending message per receiver
+/// </summary>
+[ByRefEvent]
+public record struct RadioReceiveAttemptEvent(RadioChannelPrototype Channel, EntityUid RadioSource, EntityUid RadioReceiver)
+{
+    public readonly RadioChannelPrototype Channel = Channel;
+    public readonly EntityUid RadioSource = RadioSource;
+    public readonly EntityUid RadioReceiver = RadioReceiver;
+    public bool Cancelled = false;
+}
+
+/// <summary>
+/// Use this event to cancel sending message to every receiver
+/// </summary>
+[ByRefEvent]
+public record struct RadioSendAttemptEvent(RadioChannelPrototype Channel, EntityUid RadioSource)
+{
+    public readonly RadioChannelPrototype Channel = Channel;
+    public readonly EntityUid RadioSource = RadioSource;
+    public bool Cancelled = false;
+}
diff --git a/Content.Server/Radio/RadioReceiveEvent.cs b/Content.Server/Radio/RadioReceiveEvent.cs
deleted file mode 100644 (file)
index abcee61..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-using Content.Shared.Chat;
-using Content.Shared.Radio;
-
-namespace Content.Server.Radio;
-
-[ByRefEvent]
-public struct RadioReceiveEvent
-{
-    public readonly string Message;
-    public readonly EntityUid MessageSource;
-    public readonly RadioChannelPrototype Channel;
-    public readonly MsgChatMessage ChatMsg;
-
-    public RadioReceiveEvent(string message, EntityUid messageSource, RadioChannelPrototype channel, MsgChatMessage chatMsg)
-    {
-        Message = message;
-        MessageSource = messageSource;
-        Channel = channel;
-        ChatMsg = chatMsg;
-    }
-}
-
-/// <summary>
-/// Use this event to cancel sending messages by doing various checks (e.g. range)
-/// </summary>
-[ByRefEvent]
-public struct RadioReceiveAttemptEvent
-{
-    public readonly RadioChannelPrototype Channel;
-    public readonly EntityUid RadioSource;
-    public readonly EntityUid RadioReceiver;
-
-    public bool Cancelled = false;
-
-    public RadioReceiveAttemptEvent(RadioChannelPrototype channel, EntityUid radioSource, EntityUid radioReceiver)
-    {
-        Channel = channel;
-        RadioSource = radioSource;
-        RadioReceiver = radioReceiver;
-    }
-}
diff --git a/Resources/Locale/en-US/radio/components/radio-jammer-component.ftl b/Resources/Locale/en-US/radio/components/radio-jammer-component.ftl
new file mode 100644 (file)
index 0000000..63c0913
--- /dev/null
@@ -0,0 +1,7 @@
+radio-jammer-component-on-use = The jammer is now {$state}.
+radio-jammer-component-on-state = on
+radio-jammer-component-off-state = off
+
+radio-jammer-component-examine-on-state = The light is currently [color=darkgreen]on[/color].
+radio-jammer-component-examine-off-state = The light is currently [color=darkred]off[/color].
+radio-jammer-component-charge = The battery is [color=yellow]{$charge}%[/color] full.
index e935cc982e6e143886eb46f6d4bf3aaf4f8b4dc3..ea3943d6763f5d89cdecaba3682550df04e8d661 100644 (file)
@@ -93,6 +93,9 @@ uplink-hypopen-desc = A chemical hypospray disguised as a pen, capable of instan
 uplink-voice-mask-name = Voice Mask
 uplink-voice-mask-desc = A gas mask that lets you adjust your voice to whoever you can think of. Also utilizes cutting-edge chameleon technology.
 
+uplink-radio-jammer-name = Radio Jammer
+uplink-radio-jammer-desc = This device will disrupt any nearby outgoing radio communication when activated.
+
 # Implants
 uplink-storage-implanter-name = Storage Implanter
 uplink-storage-implanter-desc = Hide goodies inside of yourself with new bluespace technology!
index 2b2a4c04678693df14714e4e563e3c66fcb30f5e..f920c1ba57b72efe6bfe935f6b4b1f46d7a6ed14 100644 (file)
   categories:
   - UplinkUtility
 
+- type: listing
+  id: UplinkRadioJammer
+  name: uplink-radio-jammer-name
+  description: uplink-radio-jammer-desc
+  productEntity: RadioJammer
+  cost:
+    Telecrystal: 5
+  categories:
+  - UplinkUtility
+
 # Implants
 
 - type: listing
diff --git a/Resources/Prototypes/Entities/Objects/Tools/jammer.yml b/Resources/Prototypes/Entities/Objects/Tools/jammer.yml
new file mode 100644 (file)
index 0000000..0021491
--- /dev/null
@@ -0,0 +1,21 @@
+- type: entity
+  name: radio jammer
+  parent: BaseItem
+  id: RadioJammer
+  description: This device will disrupt any nearby outgoing radio communication when activated.
+  components:
+  - type: Sprite
+    netsync: false
+    sprite: Objects/Devices/jammer.rsi
+    state: jammer
+  - type: RadioJammer
+  - type: PowerCellSlot
+    cellSlotId: cell_slot
+  - type: ContainerContainer
+    containers:
+      cell_slot: !type:ContainerSlot
+  - type: ItemSlots
+    slots:
+      cell_slot:
+        name: power-cell-slot-component-slot-name-default
+        startingItem: PowerCellMedium
diff --git a/Resources/Textures/Objects/Devices/jammer.rsi/jammer.png b/Resources/Textures/Objects/Devices/jammer.rsi/jammer.png
new file mode 100644 (file)
index 0000000..6de27ba
Binary files /dev/null and b/Resources/Textures/Objects/Devices/jammer.rsi/jammer.png differ
diff --git a/Resources/Textures/Objects/Devices/jammer.rsi/meta.json b/Resources/Textures/Objects/Devices/jammer.rsi/meta.json
new file mode 100644 (file)
index 0000000..2923d9a
--- /dev/null
@@ -0,0 +1,15 @@
+{
+    "version": 1,
+    "license": "CC-BY-SA-3.0",
+    "copyright": "Taken from https://github.com/tgstation/tgstation/commit/c65da5a49477413310c81c460ea4b243a9f864dd",
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "states": [
+        {
+            "name": "jammer",
+            "directions": 1
+        }
+    ]
+}
\ No newline at end of file