Add radio jammer (#14369)
This commit is contained in:
@@ -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
|
||||
{
|
||||
}
|
||||
20
Content.Server/Radio/Components/RadioJammerComponent.cs
Normal file
20
Content.Server/Radio/Components/RadioJammerComponent.cs
Normal file
@@ -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;
|
||||
}
|
||||
91
Content.Server/Radio/EntitySystems/JammerSystem.cs
Normal file
91
Content.Server/Radio/EntitySystems/JammerSystem.cs
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
30
Content.Server/Radio/RadioEvent.cs
Normal file
30
Content.Server/Radio/RadioEvent.cs
Normal file
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
@@ -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!
|
||||
|
||||
@@ -332,6 +332,16 @@
|
||||
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
|
||||
|
||||
21
Resources/Prototypes/Entities/Objects/Tools/jammer.yml
Normal file
21
Resources/Prototypes/Entities/Objects/Tools/jammer.yml
Normal file
@@ -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
|
||||
BIN
Resources/Textures/Objects/Devices/jammer.rsi/jammer.png
Normal file
BIN
Resources/Textures/Objects/Devices/jammer.rsi/jammer.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 495 B |
15
Resources/Textures/Objects/Devices/jammer.rsi/meta.json
Normal file
15
Resources/Textures/Objects/Devices/jammer.rsi/meta.json
Normal file
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user