Add radio jammer (#14369)

This commit is contained in:
Slava0135
2023-04-14 22:50:19 +03:00
committed by GitHub
parent 779100484f
commit 7886d27dda
12 changed files with 214 additions and 42 deletions

View File

@@ -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
{
}

View 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;
}

View 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;
}
}
}
}

View 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;

View 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;
}

View File

@@ -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;
}
}