Good Intercoms (#17950)
* crystal anomaly * Good intercoms * fixes * fix construction fail * Revert "crystal anomaly" This reverts commit 0d9e3f62ff82c79e72f882b9c7f4ca1b9c6e6dd8. * migration
This commit is contained in:
58
Content.Client/Radio/Ui/IntercomBoundUserInterface.cs
Normal file
58
Content.Client/Radio/Ui/IntercomBoundUserInterface.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using Content.Shared.Radio;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
|
||||
namespace Content.Client.Radio.Ui;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class IntercomBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
[ViewVariables]
|
||||
private IntercomMenu? _menu;
|
||||
|
||||
public IntercomBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_menu = new();
|
||||
|
||||
_menu.OnMicPressed += enabled =>
|
||||
{
|
||||
SendMessage(new ToggleIntercomMicMessage(enabled));
|
||||
};
|
||||
_menu.OnSpeakerPressed += enabled =>
|
||||
{
|
||||
SendMessage(new ToggleIntercomSpeakerMessage(enabled));
|
||||
};
|
||||
_menu.OnChannelSelected += channel =>
|
||||
{
|
||||
SendMessage(new SelectIntercomChannelMessage(channel));
|
||||
};
|
||||
|
||||
_menu.OnClose += Close;
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing)
|
||||
return;
|
||||
_menu?.Close();
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
|
||||
if (state is not IntercomBoundUIState msg)
|
||||
return;
|
||||
|
||||
_menu?.Update(msg);
|
||||
}
|
||||
}
|
||||
31
Content.Client/Radio/Ui/IntercomMenu.xaml
Normal file
31
Content.Client/Radio/Ui/IntercomMenu.xaml
Normal file
@@ -0,0 +1,31 @@
|
||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
Title="{Loc 'intercom-menu-title'}"
|
||||
MinSize="300 170"
|
||||
SetSize="300 170">
|
||||
<BoxContainer Orientation="Vertical"
|
||||
HorizontalExpand="True"
|
||||
VerticalExpand="True"
|
||||
Margin="5 0 5 0">
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" VerticalExpand="True">
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" HorizontalAlignment="Center">
|
||||
<Label Text="{Loc 'intercom-channel-label'}" HorizontalAlignment="Center"/>
|
||||
<OptionButton Name="ChannelOptions" VerticalExpand="True" MinWidth="125"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
<Control MinHeight="10"/>
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" HorizontalAlignment="Right" Margin="5 0 5 5">
|
||||
<Button Name="MicButton" ToggleMode="True" Text="{Loc 'intercom-button-text-mic'}" StyleClasses="OpenRight" MinWidth="70"/>
|
||||
<Button Name="SpeakerButton" ToggleMode="True" Text="{Loc 'intercom-button-text-speaker'}" StyleClasses="OpenLeft" MinWidth="70"/>
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<PanelContainer StyleClasses="LowDivider" />
|
||||
<BoxContainer Orientation="Horizontal" Margin="10 2 5 0" VerticalAlignment="Bottom">
|
||||
<Label Text="{Loc 'intercom-flavor-text-left'}" StyleClasses="WindowFooterText"
|
||||
HorizontalAlignment="Left" HorizontalExpand="True" Margin="0 0 5 0" />
|
||||
<TextureRect StyleClasses="NTLogoDark" Stretch="KeepAspectCentered"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Right" SetSize="19 19"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</controls:FancyWindow>
|
||||
55
Content.Client/Radio/Ui/IntercomMenu.xaml.cs
Normal file
55
Content.Client/Radio/Ui/IntercomMenu.xaml.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Radio;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.Radio.Ui;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class IntercomMenu : FancyWindow
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
|
||||
public event Action<bool>? OnMicPressed;
|
||||
public event Action<bool>? OnSpeakerPressed;
|
||||
public event Action<string>? OnChannelSelected;
|
||||
|
||||
private readonly List<string> _channels = new();
|
||||
|
||||
public IntercomMenu()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
MicButton.OnPressed += args => OnMicPressed?.Invoke(args.Button.Pressed);
|
||||
SpeakerButton.OnPressed += args => OnSpeakerPressed?.Invoke(args.Button.Pressed);
|
||||
}
|
||||
|
||||
public void Update(IntercomBoundUIState state)
|
||||
{
|
||||
MicButton.Pressed = state.MicEnabled;
|
||||
SpeakerButton.Pressed = state.SpeakerEnabled;
|
||||
|
||||
ChannelOptions.Clear();
|
||||
_channels.Clear();
|
||||
for (var i = 0; i < state.AvailableChannels.Count; i++)
|
||||
{
|
||||
var channel = state.AvailableChannels[i];
|
||||
if (!_prototype.TryIndex<RadioChannelPrototype>(channel, out var prototype))
|
||||
continue;
|
||||
|
||||
_channels.Add(channel);
|
||||
ChannelOptions.AddItem(Loc.GetString(prototype.Name), i);
|
||||
|
||||
if (channel == state.SelectedChannel)
|
||||
ChannelOptions.Select(i);
|
||||
}
|
||||
ChannelOptions.OnItemSelected += args =>
|
||||
{
|
||||
ChannelOptions.SelectId(args.Id);
|
||||
OnChannelSelected?.Invoke(_channels[args.Id]);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,6 @@ public sealed class RadioMicrophoneComponent : Component
|
||||
[DataField("broadcastChannel", customTypeSerializer: typeof(PrototypeIdSerializer<RadioChannelPrototype>))]
|
||||
public string BroadcastChannel = SharedChatSystem.CommonChannel;
|
||||
|
||||
[ViewVariables, DataField("supportedChannels", customTypeSerializer: typeof(PrototypeIdListSerializer<RadioChannelPrototype>))]
|
||||
public List<string>? SupportedChannels;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("listenRange")]
|
||||
public int ListenRange = 4;
|
||||
@@ -30,6 +27,13 @@ public sealed class RadioMicrophoneComponent : Component
|
||||
[DataField("powerRequired")]
|
||||
public bool PowerRequired = false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not interacting with this entity
|
||||
/// toggles it on or off.
|
||||
/// </summary>
|
||||
[DataField("toggleOnInteract")]
|
||||
public bool ToggleOnInteract = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the speaker must have an
|
||||
/// unobstructed path to the radio to speak
|
||||
|
||||
@@ -12,6 +12,13 @@ namespace Content.Server.Radio.Components;
|
||||
[Access(typeof(RadioDeviceSystem))]
|
||||
public sealed class RadioSpeakerComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether or not interacting with this entity
|
||||
/// toggles it on or off.
|
||||
/// </summary>
|
||||
[DataField("toggleOnInteract")]
|
||||
public bool ToggleOnInteract = true;
|
||||
|
||||
[DataField("channels", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<RadioChannelPrototype>))]
|
||||
public HashSet<string> Channels = new () { SharedChatSystem.CommonChannel };
|
||||
|
||||
|
||||
@@ -6,12 +6,13 @@ using Content.Server.Power.EntitySystems;
|
||||
using Content.Server.Radio.Components;
|
||||
using Content.Server.Speech;
|
||||
using Content.Server.Speech.Components;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Radio;
|
||||
using Content.Shared.Verbs;
|
||||
using Content.Shared.Radio.Components;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Radio.EntitySystems;
|
||||
@@ -27,6 +28,7 @@ public sealed class RadioDeviceSystem : EntitySystem
|
||||
[Dependency] private readonly RadioSystem _radio = default!;
|
||||
[Dependency] private readonly InteractionSystem _interaction = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
||||
|
||||
// Used to prevent a shitter from using a bunch of radios to spam chat.
|
||||
private HashSet<(string, EntityUid)> _recentlySent = new();
|
||||
@@ -39,12 +41,16 @@ public sealed class RadioDeviceSystem : EntitySystem
|
||||
SubscribeLocalEvent<RadioMicrophoneComponent, ActivateInWorldEvent>(OnActivateMicrophone);
|
||||
SubscribeLocalEvent<RadioMicrophoneComponent, ListenEvent>(OnListen);
|
||||
SubscribeLocalEvent<RadioMicrophoneComponent, ListenAttemptEvent>(OnAttemptListen);
|
||||
SubscribeLocalEvent<RadioMicrophoneComponent, GetVerbsEvent<Verb>>(OnGetVerbs);
|
||||
SubscribeLocalEvent<RadioMicrophoneComponent, PowerChangedEvent>(OnPowerChanged);
|
||||
|
||||
SubscribeLocalEvent<RadioSpeakerComponent, ComponentInit>(OnSpeakerInit);
|
||||
SubscribeLocalEvent<RadioSpeakerComponent, ActivateInWorldEvent>(OnActivateSpeaker);
|
||||
SubscribeLocalEvent<RadioSpeakerComponent, RadioReceiveEvent>(OnReceiveRadio);
|
||||
|
||||
SubscribeLocalEvent<IntercomComponent, BeforeActivatableUIOpenEvent>(OnBeforeIntercomUiOpen);
|
||||
SubscribeLocalEvent<IntercomComponent, ToggleIntercomMicMessage>(OnToggleIntercomMic);
|
||||
SubscribeLocalEvent<IntercomComponent, ToggleIntercomSpeakerMessage>(OnToggleIntercomSpeaker);
|
||||
SubscribeLocalEvent<IntercomComponent, SelectIntercomChannelMessage>(OnSelectIntercomChannel);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
@@ -75,12 +81,18 @@ public sealed class RadioDeviceSystem : EntitySystem
|
||||
#region Toggling
|
||||
private void OnActivateMicrophone(EntityUid uid, RadioMicrophoneComponent component, ActivateInWorldEvent args)
|
||||
{
|
||||
if (!component.ToggleOnInteract)
|
||||
return;
|
||||
|
||||
ToggleRadioMicrophone(uid, args.User, args.Handled, component);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnActivateSpeaker(EntityUid uid, RadioSpeakerComponent component, ActivateInWorldEvent args)
|
||||
{
|
||||
if (!component.ToggleOnInteract)
|
||||
return;
|
||||
|
||||
ToggleRadioSpeaker(uid, args.User, args.Handled, component);
|
||||
args.Handled = true;
|
||||
}
|
||||
@@ -90,71 +102,38 @@ public sealed class RadioDeviceSystem : EntitySystem
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
|
||||
if (component.PowerRequired && !this.IsPowered(uid, EntityManager))
|
||||
return;
|
||||
|
||||
SetMicrophoneEnabled(uid, !component.Enabled, component);
|
||||
|
||||
if (!quiet)
|
||||
{
|
||||
var state = Loc.GetString(component.Enabled ? "handheld-radio-component-on-state" : "handheld-radio-component-off-state");
|
||||
var message = Loc.GetString("handheld-radio-component-on-use", ("radioState", state));
|
||||
_popup.PopupEntity(message, user, user);
|
||||
}
|
||||
|
||||
if (component.Enabled)
|
||||
EnsureComp<ActiveListenerComponent>(uid).Range = component.ListenRange;
|
||||
else
|
||||
RemCompDeferred<ActiveListenerComponent>(uid);
|
||||
}
|
||||
|
||||
private void OnGetVerbs(EntityUid uid, RadioMicrophoneComponent component, GetVerbsEvent<Verb> args)
|
||||
{
|
||||
if (!args.CanAccess || !args.CanInteract || args.Hands == null)
|
||||
return;
|
||||
|
||||
if (component.SupportedChannels == null || component.SupportedChannels.Count <= 1)
|
||||
return;
|
||||
|
||||
if (component.PowerRequired && !this.IsPowered(uid, EntityManager))
|
||||
return;
|
||||
|
||||
foreach (var channel in component.SupportedChannels)
|
||||
{
|
||||
var proto = _protoMan.Index<RadioChannelPrototype>(channel);
|
||||
|
||||
var v = new Verb
|
||||
{
|
||||
Text = proto.LocalizedName,
|
||||
Priority = 1,
|
||||
Category = VerbCategory.ChannelSelect,
|
||||
Disabled = component.BroadcastChannel == channel,
|
||||
DoContactInteraction = true,
|
||||
Act = () =>
|
||||
{
|
||||
component.BroadcastChannel = channel;
|
||||
_popup.PopupEntity(Loc.GetString("handheld-radio-component-channel-set",
|
||||
("channel", channel)), uid, args.User);
|
||||
}
|
||||
};
|
||||
args.Verbs.Add(v);
|
||||
}
|
||||
SetMicrophoneEnabled(uid, user, !component.Enabled, quiet, component);
|
||||
}
|
||||
|
||||
private void OnPowerChanged(EntityUid uid, RadioMicrophoneComponent component, ref PowerChangedEvent args)
|
||||
{
|
||||
if (args.Powered)
|
||||
return;
|
||||
SetMicrophoneEnabled(uid, false, component);
|
||||
SetMicrophoneEnabled(uid, null, false, true, component);
|
||||
}
|
||||
|
||||
public void SetMicrophoneEnabled(EntityUid uid, bool enabled, RadioMicrophoneComponent? component = null)
|
||||
public void SetMicrophoneEnabled(EntityUid uid, EntityUid? user, bool enabled, bool quiet = false, RadioMicrophoneComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component, false))
|
||||
return;
|
||||
|
||||
if (component.PowerRequired && !this.IsPowered(uid, EntityManager))
|
||||
return;
|
||||
|
||||
component.Enabled = enabled;
|
||||
|
||||
if (!quiet && user != null)
|
||||
{
|
||||
var state = Loc.GetString(component.Enabled ? "handheld-radio-component-on-state" : "handheld-radio-component-off-state");
|
||||
var message = Loc.GetString("handheld-radio-component-on-use", ("radioState", state));
|
||||
_popup.PopupEntity(message, user.Value, user.Value);
|
||||
}
|
||||
|
||||
_appearance.SetData(uid, RadioDeviceVisuals.Broadcasting, component.Enabled);
|
||||
if (component.Enabled)
|
||||
EnsureComp<ActiveListenerComponent>(uid).Range = component.ListenRange;
|
||||
else
|
||||
RemCompDeferred<ActiveListenerComponent>(uid);
|
||||
}
|
||||
|
||||
public void ToggleRadioSpeaker(EntityUid uid, EntityUid user, bool quiet = false, RadioSpeakerComponent? component = null)
|
||||
@@ -162,7 +141,15 @@ public sealed class RadioDeviceSystem : EntitySystem
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
|
||||
component.Enabled = !component.Enabled;
|
||||
SetSpeakerEnabled(uid, user, !component.Enabled, quiet, component);
|
||||
}
|
||||
|
||||
public void SetSpeakerEnabled(EntityUid uid, EntityUid user, bool enabled, bool quiet = false, RadioSpeakerComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
|
||||
component.Enabled = enabled;
|
||||
|
||||
if (!quiet)
|
||||
{
|
||||
@@ -171,6 +158,7 @@ public sealed class RadioDeviceSystem : EntitySystem
|
||||
_popup.PopupEntity(message, user, user);
|
||||
}
|
||||
|
||||
_appearance.SetData(uid, RadioDeviceVisuals.Speaker, component.Enabled);
|
||||
if (component.Enabled)
|
||||
EnsureComp<ActiveRadioComponent>(uid).Channels.UnionWith(component.Channels);
|
||||
else
|
||||
@@ -215,6 +203,57 @@ public sealed class RadioDeviceSystem : EntitySystem
|
||||
("originalName", nameEv.Name));
|
||||
|
||||
// log to chat so people can identity the speaker/source, but avoid clogging ghost chat if there are many radios
|
||||
_chat.TrySendInGameICMessage(uid, args.Message, InGameICChatType.Speak, ChatTransmitRange.GhostRangeLimit, nameOverride: name, checkRadioPrefix: false);
|
||||
_chat.TrySendInGameICMessage(uid, args.Message, InGameICChatType.Whisper, ChatTransmitRange.GhostRangeLimit, nameOverride: name, checkRadioPrefix: false);
|
||||
}
|
||||
|
||||
private void OnBeforeIntercomUiOpen(EntityUid uid, IntercomComponent component, BeforeActivatableUIOpenEvent args)
|
||||
{
|
||||
UpdateIntercomUi(uid, component);
|
||||
}
|
||||
|
||||
private void OnToggleIntercomMic(EntityUid uid, IntercomComponent component, ToggleIntercomMicMessage args)
|
||||
{
|
||||
if (component.RequiresPower && !this.IsPowered(uid, EntityManager) || args.Session.AttachedEntity is not { } user)
|
||||
return;
|
||||
|
||||
SetMicrophoneEnabled(uid, user, args.Enabled, true);
|
||||
UpdateIntercomUi(uid, component);
|
||||
}
|
||||
|
||||
private void OnToggleIntercomSpeaker(EntityUid uid, IntercomComponent component, ToggleIntercomSpeakerMessage args)
|
||||
{
|
||||
if (component.RequiresPower && !this.IsPowered(uid, EntityManager) || args.Session.AttachedEntity is not { } user)
|
||||
return;
|
||||
|
||||
SetSpeakerEnabled(uid, user, args.Enabled, true);
|
||||
UpdateIntercomUi(uid, component);
|
||||
}
|
||||
|
||||
private void OnSelectIntercomChannel(EntityUid uid, IntercomComponent component, SelectIntercomChannelMessage args)
|
||||
{
|
||||
if (component.RequiresPower && !this.IsPowered(uid, EntityManager) || args.Session.AttachedEntity is not { })
|
||||
return;
|
||||
|
||||
if (!_protoMan.TryIndex<RadioChannelPrototype>(args.Channel, out _) || !component.SupportedChannels.Contains(args.Channel))
|
||||
return;
|
||||
|
||||
if (TryComp<RadioMicrophoneComponent>(uid, out var mic))
|
||||
mic.BroadcastChannel = args.Channel;
|
||||
if (TryComp<RadioSpeakerComponent>(uid, out var speaker))
|
||||
speaker.Channels = new(){ args.Channel };
|
||||
UpdateIntercomUi(uid, component);
|
||||
}
|
||||
|
||||
private void UpdateIntercomUi(EntityUid uid, IntercomComponent component)
|
||||
{
|
||||
var micComp = CompOrNull<RadioMicrophoneComponent>(uid);
|
||||
var speakerComp = CompOrNull<RadioSpeakerComponent>(uid);
|
||||
|
||||
var micEnabled = micComp?.Enabled ?? false;
|
||||
var speakerEnabled = speakerComp?.Enabled ?? false;
|
||||
var availableChannels = component.SupportedChannels;
|
||||
var selectedChannel = micComp?.BroadcastChannel ?? SharedChatSystem.CommonChannel;
|
||||
var state = new IntercomBoundUIState(micEnabled, speakerEnabled, availableChannels, selectedChannel);
|
||||
_ui.TrySetUiState(uid, IntercomUiKey.Key, state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ public sealed class RadioSystem : EntitySystem
|
||||
var sentAtLeastOnce = false;
|
||||
while (canSend && radioQuery.MoveNext(out var receiver, out var radio, out var transform))
|
||||
{
|
||||
if (!radio.Channels.Contains(channel.ID))
|
||||
if (!radio.Channels.Contains(channel.ID) || (TryComp<IntercomComponent>(receiver, out var intercom) && !intercom.SupportedChannels.Contains(channel.ID)))
|
||||
continue;
|
||||
|
||||
if (!channel.LongRange && transform.MapID != sourceMapId && !radio.GlobalReceive)
|
||||
|
||||
23
Content.Shared/Radio/Components/IntercomComponent.cs
Normal file
23
Content.Shared/Radio/Components/IntercomComponent.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||
|
||||
namespace Content.Shared.Radio.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Handles intercom ui and is authoritative on the channels an intercom can access.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class IntercomComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Does this intercom require popwer to function
|
||||
/// </summary>
|
||||
[DataField("requiresPower"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool RequiresPower = true;
|
||||
|
||||
/// <summary>
|
||||
/// The list of radio channel prototypes this intercom can choose between.
|
||||
/// </summary>
|
||||
[DataField("supportedChannels", customTypeSerializer: typeof(PrototypeIdListSerializer<RadioChannelPrototype>))]
|
||||
public List<string> SupportedChannels = new();
|
||||
}
|
||||
@@ -5,11 +5,13 @@ namespace Content.Shared.Radio;
|
||||
[Serializable, NetSerializable]
|
||||
public enum RadioDeviceVisuals : byte
|
||||
{
|
||||
Broadcasting
|
||||
Broadcasting,
|
||||
Speaker
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum RadioDeviceVisualLayers : byte
|
||||
{
|
||||
Broadcasting
|
||||
Broadcasting,
|
||||
Speaker
|
||||
}
|
||||
|
||||
59
Content.Shared/Radio/SharedIntercom.cs
Normal file
59
Content.Shared/Radio/SharedIntercom.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Radio;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum IntercomUiKey
|
||||
{
|
||||
Key,
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class IntercomBoundUIState : BoundUserInterfaceState
|
||||
{
|
||||
public bool MicEnabled;
|
||||
public bool SpeakerEnabled;
|
||||
public List<string> AvailableChannels;
|
||||
public string SelectedChannel;
|
||||
|
||||
public IntercomBoundUIState(bool micEnabled, bool speakerEnabled, List<string> availableChannels, string selectedChannel)
|
||||
{
|
||||
MicEnabled = micEnabled;
|
||||
SpeakerEnabled = speakerEnabled;
|
||||
AvailableChannels = availableChannels;
|
||||
SelectedChannel = selectedChannel;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class ToggleIntercomMicMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public bool Enabled;
|
||||
|
||||
public ToggleIntercomMicMessage(bool enabled)
|
||||
{
|
||||
Enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class ToggleIntercomSpeakerMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public bool Enabled;
|
||||
|
||||
public ToggleIntercomSpeakerMessage(bool enabled)
|
||||
{
|
||||
Enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class SelectIntercomChannelMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public string Channel;
|
||||
|
||||
public SelectIntercomChannelMessage(string channel)
|
||||
{
|
||||
Channel = channel;
|
||||
}
|
||||
}
|
||||
5
Resources/Locale/en-US/radio/components/intercom.ftl
Normal file
5
Resources/Locale/en-US/radio/components/intercom.ftl
Normal file
@@ -0,0 +1,5 @@
|
||||
intercom-menu-title = Intercom
|
||||
intercom-channel-label = Channel:
|
||||
intercom-button-text-mic = Mic.
|
||||
intercom-button-text-speaker = Speak
|
||||
intercom-flavor-text-left = Keep lines free of chatter
|
||||
@@ -51,6 +51,8 @@
|
||||
type: TransferAmountBoundUserInterface
|
||||
- key: enum.InstrumentUiKey.Key
|
||||
type: InstrumentBoundUserInterface
|
||||
- key: enum.IntercomUiKey.Key
|
||||
type: IntercomBoundUserInterface
|
||||
- type: Appearance
|
||||
- type: Item
|
||||
size: 40
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
type: TransferAmountBoundUserInterface
|
||||
- key: enum.InstrumentUiKey.Key
|
||||
type: InstrumentBoundUserInterface
|
||||
- key: enum.IntercomUiKey.Key
|
||||
type: IntercomBoundUserInterface
|
||||
- type: Reactive
|
||||
groups:
|
||||
Acidic: [Touch]
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
id: Intercom
|
||||
name: intercom
|
||||
description: An intercom. For when the station just needs to know something.
|
||||
abstract: true
|
||||
components:
|
||||
- type: WallMount
|
||||
- type: ApcPowerReceiver
|
||||
@@ -12,6 +13,11 @@
|
||||
powerRequired: true
|
||||
unobstructedRequired: true
|
||||
listenRange: 2
|
||||
toggleOnInteract: false
|
||||
- type: RadioSpeaker
|
||||
toggleOnInteract: false
|
||||
- type: Intercom
|
||||
- type: Speech
|
||||
- type: ExtensionCableReceiver
|
||||
- type: Clickable
|
||||
- type: InteractionOutline
|
||||
@@ -23,10 +29,15 @@
|
||||
- state: base
|
||||
- state: unshaded
|
||||
map: ["enum.PowerDeviceVisualLayers.Powered"]
|
||||
shader: unshaded
|
||||
- state: broadcasting
|
||||
map: ["enum.RadioDeviceVisualLayers.Broadcasting"]
|
||||
shader: unshaded
|
||||
visible: false
|
||||
- state: speaker
|
||||
map: ["enum.RadioDeviceVisualLayers.Speaker"]
|
||||
shader: unshaded
|
||||
visible: false
|
||||
- type: Transform
|
||||
noRot: false
|
||||
anchored: true
|
||||
@@ -34,6 +45,13 @@
|
||||
- type: Wires
|
||||
BoardName: "Intercom"
|
||||
LayoutId: Intercom
|
||||
- type: ActivatableUIRequiresPower
|
||||
- type: ActivatableUI
|
||||
key: enum.IntercomUiKey.Key
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
- key: enum.IntercomUiKey.Key
|
||||
type: IntercomBoundUserInterface
|
||||
- type: Construction
|
||||
graph: Intercom
|
||||
node: intercom
|
||||
@@ -67,6 +85,10 @@
|
||||
enum.RadioDeviceVisualLayers.Broadcasting:
|
||||
True: { visible: true }
|
||||
False: { visible: false }
|
||||
enum.RadioDeviceVisuals.Speaker:
|
||||
enum.RadioDeviceVisualLayers.Speaker:
|
||||
True: { visible: true }
|
||||
False: { visible: false }
|
||||
placement:
|
||||
mode: SnapgridCenter
|
||||
snap:
|
||||
@@ -93,15 +115,21 @@
|
||||
snap:
|
||||
- Wallmount
|
||||
|
||||
- type: entity
|
||||
id: IntercomCommon
|
||||
parent: Intercom
|
||||
suffix: Common
|
||||
components:
|
||||
- type: Intercom
|
||||
supportedChannels:
|
||||
- Common
|
||||
|
||||
- type: entity
|
||||
id: IntercomCommand
|
||||
parent: Intercom
|
||||
suffix: Command
|
||||
components:
|
||||
- type: RadioMicrophone
|
||||
powerRequired: true
|
||||
unobstructedRequired: true
|
||||
listenRange: 2
|
||||
- type: Intercom
|
||||
supportedChannels:
|
||||
- Common
|
||||
- Command
|
||||
@@ -111,10 +139,7 @@
|
||||
parent: Intercom
|
||||
suffix: Engineering
|
||||
components:
|
||||
- type: RadioMicrophone
|
||||
powerRequired: true
|
||||
unobstructedRequired: true
|
||||
listenRange: 2
|
||||
- type: Intercom
|
||||
supportedChannels:
|
||||
- Common
|
||||
- Engineering
|
||||
@@ -124,10 +149,7 @@
|
||||
parent: Intercom
|
||||
suffix: Medical
|
||||
components:
|
||||
- type: RadioMicrophone
|
||||
powerRequired: true
|
||||
unobstructedRequired: true
|
||||
listenRange: 2
|
||||
- type: Intercom
|
||||
supportedChannels:
|
||||
- Common
|
||||
- Medical
|
||||
@@ -137,10 +159,7 @@
|
||||
parent: Intercom
|
||||
suffix: Science
|
||||
components:
|
||||
- type: RadioMicrophone
|
||||
powerRequired: true
|
||||
unobstructedRequired: true
|
||||
listenRange: 2
|
||||
- type: Intercom
|
||||
supportedChannels:
|
||||
- Common
|
||||
- Science
|
||||
@@ -150,10 +169,7 @@
|
||||
parent: Intercom
|
||||
suffix: Security
|
||||
components:
|
||||
- type: RadioMicrophone
|
||||
powerRequired: true
|
||||
unobstructedRequired: true
|
||||
listenRange: 2
|
||||
- type: Intercom
|
||||
supportedChannels:
|
||||
- Common
|
||||
- Security
|
||||
@@ -163,10 +179,7 @@
|
||||
parent: Intercom
|
||||
suffix: Service
|
||||
components:
|
||||
- type: RadioMicrophone
|
||||
powerRequired: true
|
||||
unobstructedRequired: true
|
||||
listenRange: 2
|
||||
- type: Intercom
|
||||
supportedChannels:
|
||||
- Common
|
||||
- Service
|
||||
@@ -176,10 +189,7 @@
|
||||
parent: Intercom
|
||||
suffix: Supply
|
||||
components:
|
||||
- type: RadioMicrophone
|
||||
powerRequired: true
|
||||
unobstructedRequired: true
|
||||
listenRange: 2
|
||||
- type: Intercom
|
||||
supportedChannels:
|
||||
- Common
|
||||
- Supply
|
||||
@@ -189,10 +199,7 @@
|
||||
parent: Intercom
|
||||
suffix: All
|
||||
components:
|
||||
- type: RadioMicrophone
|
||||
powerRequired: true
|
||||
unobstructedRequired: true
|
||||
listenRange: 2
|
||||
- type: Intercom
|
||||
supportedChannels:
|
||||
- Common
|
||||
- Command
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
- id: RandomPainting
|
||||
prob: 0.05
|
||||
orGroup: content
|
||||
- id: Intercom
|
||||
- id: IntercomCommon
|
||||
prob: 0.1
|
||||
orGroup: content
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
- id: RandomPainting
|
||||
prob: 0.05
|
||||
orGroup: content
|
||||
- id: Intercom
|
||||
- id: IntercomCommon
|
||||
prob: 0.1
|
||||
orGroup: content
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
doAfter: 2
|
||||
|
||||
- node: intercom
|
||||
entity: Intercom #TODO: make this work with encryption keys
|
||||
entity: IntercomCommon #TODO: make this work with encryption keys
|
||||
edges:
|
||||
- to: wired
|
||||
conditions:
|
||||
|
||||
@@ -7,7 +7,15 @@
|
||||
permanentComponents:
|
||||
- type: RadioMicrophone
|
||||
powerRequired: false
|
||||
toggleOnInteract: false
|
||||
listenRange: 3
|
||||
- type: Speech
|
||||
- type: RadioSpeaker
|
||||
toggleOnInteract: false
|
||||
- type: ActivatableUI
|
||||
key: enum.IntercomUiKey.Key
|
||||
- type: Intercom
|
||||
requiresPower: false
|
||||
supportedChannels:
|
||||
- Common
|
||||
- CentCom
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
"name": "build",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "speaker",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "unshaded",
|
||||
"directions": 4
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 157 B |
Binary file not shown.
|
Before Width: | Height: | Size: 369 B After Width: | Height: | Size: 328 B |
@@ -102,3 +102,6 @@ ClothingHeadHelmetHelmetOld: ClothingHeadHelmetBasic
|
||||
# 2023-07-04
|
||||
# Bulletproof armor is almost statistically identical to kevlar, however, before this kevlar armor was the closest thing there was to "basic" armor. It makes the most sense to replace it with this.
|
||||
ClothingOuterVestKevlar: ClothingOuterArmorBasic
|
||||
|
||||
# 2023-07-10
|
||||
Intercom: IntercomCommon
|
||||
|
||||
Reference in New Issue
Block a user