Hackable intercoms (#23984)
* Enable wire interface for intercom * Implement BlockListening component and system * Implement ListenWireAction * Added cooldown/overload to mic wire pulse * Properly persist voicemask settings when user already has one. * Addressed requested changes * Added wire panel open/closed visuals
This commit is contained in:
@@ -847,6 +847,16 @@ public sealed partial class ChatSystem : SharedChatSystem
|
||||
return modifiedMessage.ToString();
|
||||
}
|
||||
|
||||
public string BuildGibberishString(IReadOnlyList<char> charOptions, int length)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
sb.Append(_random.Pick(charOptions));
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
11
Content.Server/Speech/Components/BlockListeningComponent.cs
Normal file
11
Content.Server/Speech/Components/BlockListeningComponent.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
namespace Content.Server.Speech.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Causes all ListenAttemptEvents to fail on the entity.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class BlockListeningComponent : Component
|
||||
{
|
||||
|
||||
}
|
||||
111
Content.Server/Speech/Components/ListenWireAction.cs
Normal file
111
Content.Server/Speech/Components/ListenWireAction.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
using System.Text;
|
||||
|
||||
using Content.Server.Speech.Components;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.Speech.EntitySystems;
|
||||
using Content.Server.VoiceMask;
|
||||
using Content.Server.Wires;
|
||||
using Content.Shared.Speech;
|
||||
using Content.Shared.Wires;
|
||||
|
||||
namespace Content.Server.Speech;
|
||||
|
||||
public sealed partial class ListenWireAction : BaseToggleWireAction
|
||||
{
|
||||
private WiresSystem _wires = default!;
|
||||
private ChatSystem _chat = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Length of the gibberish string sent when pulsing the wire
|
||||
/// </summary>
|
||||
private int _noiseLength = 16;
|
||||
public override Color Color { get; set; } = Color.Green;
|
||||
public override string Name { get; set; } = "wire-name-listen";
|
||||
|
||||
public override object? StatusKey { get; } = ListenWireActionKey.StatusKey;
|
||||
|
||||
public override object? TimeoutKey { get; } = ListenWireActionKey.TimeoutKey;
|
||||
|
||||
public override int Delay { get; } = 10;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_wires = EntityManager.System<WiresSystem>();
|
||||
_chat = EntityManager.System<ChatSystem>();
|
||||
}
|
||||
public override StatusLightState? GetLightState(Wire wire)
|
||||
{
|
||||
if (GetValue(wire.Owner))
|
||||
return StatusLightState.On;
|
||||
else
|
||||
{
|
||||
if (TimeoutKey != null && _wires.HasData(wire.Owner, TimeoutKey))
|
||||
return StatusLightState.BlinkingSlow;
|
||||
return StatusLightState.Off;
|
||||
}
|
||||
}
|
||||
public override void ToggleValue(EntityUid owner, bool setting)
|
||||
{
|
||||
if (setting)
|
||||
{
|
||||
// If we defer removal, the status light gets out of sync
|
||||
EntityManager.RemoveComponent<BlockListeningComponent>(owner);
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityManager.EnsureComponent<BlockListeningComponent>(owner);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool GetValue(EntityUid owner)
|
||||
{
|
||||
return !EntityManager.HasComponent<BlockListeningComponent>(owner);
|
||||
}
|
||||
|
||||
public override void Pulse(EntityUid user, Wire wire)
|
||||
{
|
||||
if (!GetValue(wire.Owner) || !IsPowered(wire.Owner))
|
||||
return;
|
||||
|
||||
// We have to use a valid euid in the ListenEvent. The user seems
|
||||
// like a sensible choice, but we need to mask their name.
|
||||
|
||||
// Save the user's existing voicemask if they have one
|
||||
var oldEnabled = true;
|
||||
var oldVoiceName = Loc.GetString("wire-listen-pulse-error-name");
|
||||
if (EntityManager.TryGetComponent<VoiceMaskComponent>(user, out var oldMask))
|
||||
{
|
||||
oldEnabled = oldMask.Enabled;
|
||||
oldVoiceName = oldMask.VoiceName;
|
||||
}
|
||||
|
||||
// Give the user a temporary voicemask component
|
||||
var mask = EntityManager.EnsureComponent<VoiceMaskComponent>(user);
|
||||
mask.Enabled = true;
|
||||
mask.VoiceName = Loc.GetString("wire-listen-pulse-identifier");
|
||||
|
||||
var chars = Loc.GetString("wire-listen-pulse-characters").ToCharArray();
|
||||
var noiseMsg = _chat.BuildGibberishString(chars, _noiseLength);
|
||||
|
||||
var attemptEv = new ListenAttemptEvent(wire.Owner);
|
||||
EntityManager.EventBus.RaiseLocalEvent(wire.Owner, attemptEv);
|
||||
if (!attemptEv.Cancelled)
|
||||
{
|
||||
var ev = new ListenEvent(noiseMsg, user);
|
||||
EntityManager.EventBus.RaiseLocalEvent(wire.Owner, ev);
|
||||
}
|
||||
|
||||
// Remove the voicemask component, or set it back to what it was before
|
||||
if (oldMask == null)
|
||||
EntityManager.RemoveComponent(user, mask);
|
||||
else
|
||||
{
|
||||
mask.Enabled = oldEnabled;
|
||||
mask.VoiceName = oldVoiceName;
|
||||
}
|
||||
|
||||
base.Pulse(user, wire);
|
||||
}
|
||||
}
|
||||
18
Content.Server/Speech/EntitySystems/BlockListeningSystem.cs
Normal file
18
Content.Server/Speech/EntitySystems/BlockListeningSystem.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Content.Server.Speech.Components;
|
||||
|
||||
namespace Content.Server.Speech.EntitySystems;
|
||||
|
||||
public sealed class BlockListeningSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<BlockListeningComponent, ListenAttemptEvent>(OnListenAttempt);
|
||||
}
|
||||
|
||||
private void OnListenAttempt(EntityUid uid, BlockListeningComponent component, ListenAttemptEvent args)
|
||||
{
|
||||
args.Cancel();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Speech;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum ListenWireActionKey : byte
|
||||
{
|
||||
StatusKey,
|
||||
TimeoutKey,
|
||||
}
|
||||
3
Resources/Locale/en-US/speech/listen-wire-action.ftl
Normal file
3
Resources/Locale/en-US/speech/listen-wire-action.ftl
Normal file
@@ -0,0 +1,3 @@
|
||||
wire-listen-pulse-identifier = electricity
|
||||
wire-listen-pulse-characters = eee EEo
|
||||
wire-listen-pulse-error-name = ERROR
|
||||
@@ -64,3 +64,4 @@ wire-name-bomb-proceed = PRCD
|
||||
wire-name-bomb-boom = BOOM
|
||||
wire-name-bomb-bolt = BOLT
|
||||
wire-name-speech = SPKR
|
||||
wire-name-listen = MIC
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
- type: Clickable
|
||||
- type: InteractionOutline
|
||||
- type: Appearance
|
||||
- type: WiresVisuals
|
||||
- type: ContainerFill
|
||||
containers:
|
||||
board: [ IntercomElectronics ]
|
||||
@@ -46,6 +47,10 @@
|
||||
map: ["enum.RadioDeviceVisualLayers.Speaker"]
|
||||
shader: unshaded
|
||||
visible: false
|
||||
- state: panel
|
||||
map: ["enum.WiresVisualLayers.MaintenancePanel"]
|
||||
shader: unshaded
|
||||
visible: false
|
||||
- type: Transform
|
||||
noRot: false
|
||||
anchored: true
|
||||
@@ -60,6 +65,8 @@
|
||||
interfaces:
|
||||
- key: enum.IntercomUiKey.Key
|
||||
type: IntercomBoundUserInterface
|
||||
- key: enum.WiresUiKey.Key
|
||||
type: WiresBoundUserInterface
|
||||
- type: Construction
|
||||
graph: Intercom
|
||||
node: intercom
|
||||
@@ -87,6 +94,10 @@
|
||||
volume: -4
|
||||
- type: GenericVisualizer
|
||||
visuals:
|
||||
enum.WiresVisualLayers.MaintenancePanel:
|
||||
enum.WiresVisualLayers.MaintenancePanel:
|
||||
True: { visible: true }
|
||||
False: { visible: false }
|
||||
enum.PowerDeviceVisuals.Powered:
|
||||
enum.PowerDeviceVisualLayers.Powered:
|
||||
True: { visible: true }
|
||||
|
||||
@@ -49,6 +49,13 @@
|
||||
- !type:AirAlarmPanicWire
|
||||
- !type:AtmosMonitorDeviceNetWire
|
||||
|
||||
- type: wireLayout
|
||||
id: Intercom
|
||||
wires:
|
||||
- !type:PowerWireAction
|
||||
- !type:SpeechWireAction
|
||||
- !type:ListenWireAction
|
||||
|
||||
- type: wireLayout
|
||||
id: FireAlarm
|
||||
wires:
|
||||
|
||||
@@ -26,6 +26,10 @@
|
||||
{
|
||||
"name": "unshaded",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "panel",
|
||||
"directions": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
BIN
Resources/Textures/Structures/Wallmounts/intercom.rsi/panel.png
Normal file
BIN
Resources/Textures/Structures/Wallmounts/intercom.rsi/panel.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 656 B |
Reference in New Issue
Block a user