]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Intercom buffs and fixes (#29580)
authorNemanja <98561806+EmoGarbage404@users.noreply.github.com>
Sun, 7 Jul 2024 14:19:10 +0000 (10:19 -0400)
committerGitHub <noreply@github.com>
Sun, 7 Jul 2024 14:19:10 +0000 (00:19 +1000)
* Intercom buffs and fixes

* remove unused bui state

* mild sec intercom buff

* reinforce sec intercoms

22 files changed:
Content.Client/Radio/EntitySystems/RadioDeviceSystem.cs [new file with mode: 0644]
Content.Client/Radio/Ui/IntercomBoundUserInterface.cs
Content.Client/Radio/Ui/IntercomMenu.xaml.cs
Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs
Content.Server/Radio/EntitySystems/RadioSystem.cs
Content.Shared/Radio/Components/IntercomComponent.cs
Content.Shared/Radio/Components/TelecomExemptComponent.cs [new file with mode: 0644]
Content.Shared/Radio/EntitySystems/EncryptionKeySystem.cs
Content.Shared/Radio/SharedIntercom.cs
Content.Shared/Wires/SharedWiresSystem.cs
Resources/Locale/en-US/radio/components/intercom.ftl
Resources/Prototypes/Entities/Objects/Devices/radio.yml
Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml
Resources/Prototypes/Recipes/Construction/Graphs/utilities/intercom.yml
Resources/Prototypes/Recipes/Construction/utilities.yml
Resources/Textures/Structures/Wallmounts/intercom.rsi/base.png
Resources/Textures/Structures/Wallmounts/intercom.rsi/broadcasting.png
Resources/Textures/Structures/Wallmounts/intercom.rsi/build.png
Resources/Textures/Structures/Wallmounts/intercom.rsi/panel.png
Resources/Textures/Structures/Wallmounts/intercom.rsi/speaker.png
Resources/Textures/Structures/Wallmounts/intercom.rsi/unshaded.png
Resources/migration.yml

diff --git a/Content.Client/Radio/EntitySystems/RadioDeviceSystem.cs b/Content.Client/Radio/EntitySystems/RadioDeviceSystem.cs
new file mode 100644 (file)
index 0000000..29d6c63
--- /dev/null
@@ -0,0 +1,23 @@
+using Content.Client.Radio.Ui;
+using Content.Shared.Radio;
+using Content.Shared.Radio.Components;
+using Robust.Client.GameObjects;
+
+namespace Content.Client.Radio.EntitySystems;
+
+public sealed class RadioDeviceSystem : EntitySystem
+{
+    [Dependency] private readonly UserInterfaceSystem _ui = default!;
+
+    /// <inheritdoc/>
+    public override void Initialize()
+    {
+        SubscribeLocalEvent<IntercomComponent, AfterAutoHandleStateEvent>(OnAfterHandleState);
+    }
+
+    private void OnAfterHandleState(Entity<IntercomComponent> ent, ref AfterAutoHandleStateEvent args)
+    {
+        if (_ui.TryGetOpenUi<IntercomBoundUserInterface>(ent.Owner, IntercomUiKey.Key, out var bui))
+            bui.Update(ent);
+    }
+}
index abbb1d58ec4b843f91c85c7a7b20be9ce374cef0..7b3e39aa084b11a486e874594d54d920a6c453f9 100644 (file)
@@ -1,6 +1,6 @@
 using Content.Shared.Radio;
+using Content.Shared.Radio.Components;
 using JetBrains.Annotations;
-using Robust.Client.GameObjects;
 
 namespace Content.Client.Radio.Ui;
 
@@ -19,7 +19,9 @@ public sealed class IntercomBoundUserInterface : BoundUserInterface
     {
         base.Open();
 
-        _menu = new();
+        var comp = EntMan.GetComponent<IntercomComponent>(Owner);
+
+        _menu = new((Owner, comp));
 
         _menu.OnMicPressed += enabled =>
         {
@@ -46,13 +48,8 @@ public sealed class IntercomBoundUserInterface : BoundUserInterface
         _menu?.Close();
     }
 
-    protected override void UpdateState(BoundUserInterfaceState state)
+    public void Update(Entity<IntercomComponent> ent)
     {
-        base.UpdateState(state);
-
-        if (state is not IntercomBoundUIState msg)
-            return;
-
-        _menu?.Update(msg);
+        _menu?.Update(ent);
     }
 }
index 8b4b38753c1dbf405685fbe22207b7c80493ed38..2e08913051c8bcaa74f9015cebc7e68ab1b511e1 100644 (file)
@@ -1,8 +1,9 @@
 using Content.Client.UserInterface.Controls;
-using Content.Shared.Radio;
+using Content.Shared.Radio.Components;
 using Robust.Client.AutoGenerated;
 using Robust.Client.UserInterface.XAML;
 using Robust.Shared.Prototypes;
+using Robust.Shared.Utility;
 
 namespace Content.Client.Radio.Ui;
 
@@ -17,38 +18,54 @@ public sealed partial class IntercomMenu : FancyWindow
 
     private readonly List<string> _channels = new();
 
-    public IntercomMenu()
+    public IntercomMenu(Entity<IntercomComponent> entity)
     {
         RobustXamlLoader.Load(this);
         IoCManager.InjectDependencies(this);
 
         MicButton.OnPressed += args => OnMicPressed?.Invoke(args.Button.Pressed);
         SpeakerButton.OnPressed += args => OnSpeakerPressed?.Invoke(args.Button.Pressed);
+
+        Update(entity);
     }
 
-    public void Update(IntercomBoundUIState state)
+    public void Update(Entity<IntercomComponent> entity)
     {
-        MicButton.Pressed = state.MicEnabled;
-        SpeakerButton.Pressed = state.SpeakerEnabled;
+        MicButton.Pressed = entity.Comp.MicrophoneEnabled;
+        SpeakerButton.Pressed = entity.Comp.SpeakerEnabled;
+
+        MicButton.Disabled = entity.Comp.SupportedChannels.Count == 0;
+        SpeakerButton.Disabled = entity.Comp.SupportedChannels.Count == 0;
+        ChannelOptions.Disabled = entity.Comp.SupportedChannels.Count == 0;
 
         ChannelOptions.Clear();
         _channels.Clear();
-        for (var i = 0; i < state.AvailableChannels.Count; i++)
+        for (var i = 0; i < entity.Comp.SupportedChannels.Count; i++)
         {
-            var channel = state.AvailableChannels[i];
-            if (!_prototype.TryIndex<RadioChannelPrototype>(channel, out var prototype))
+            var channel = entity.Comp.SupportedChannels[i];
+            if (!_prototype.TryIndex(channel, out var prototype))
                 continue;
 
             _channels.Add(channel);
             ChannelOptions.AddItem(Loc.GetString(prototype.Name), i);
 
-            if (channel == state.SelectedChannel)
+            if (channel == entity.Comp.CurrentChannel)
                 ChannelOptions.Select(i);
         }
+
+        if (entity.Comp.SupportedChannels.Count == 0)
+        {
+            ChannelOptions.AddItem(Loc.GetString("intercom-options-none"), 0);
+            ChannelOptions.Select(0);
+        }
+
         ChannelOptions.OnItemSelected += args =>
         {
+            if (!_channels.TryGetValue(args.Id, out var proto))
+                return;
+
             ChannelOptions.SelectId(args.Id);
-            OnChannelSelected?.Invoke(_channels[args.Id]);
+            OnChannelSelected?.Invoke(proto);
         };
     }
 }
index 8484fb2336384f17b3824ee49a2e61fef8167835..1258e0b8c7ebce50233202fc5b71a69ee3991db9 100644 (file)
@@ -1,3 +1,4 @@
+using System.Linq;
 using Content.Server.Chat.Systems;
 using Content.Server.Interaction;
 using Content.Server.Popups;
@@ -6,13 +7,10 @@ using Content.Server.Power.EntitySystems;
 using Content.Server.Radio.Components;
 using Content.Server.Speech;
 using Content.Server.Speech.Components;
-using Content.Shared.UserInterface;
-using Content.Shared.Chat;
 using Content.Shared.Examine;
 using Content.Shared.Interaction;
 using Content.Shared.Radio;
 using Content.Shared.Radio.Components;
-using Robust.Server.GameObjects;
 using Robust.Shared.Prototypes;
 
 namespace Content.Server.Radio.EntitySystems;
@@ -28,7 +26,6 @@ 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();
@@ -47,7 +44,7 @@ public sealed class RadioDeviceSystem : EntitySystem
         SubscribeLocalEvent<RadioSpeakerComponent, ActivateInWorldEvent>(OnActivateSpeaker);
         SubscribeLocalEvent<RadioSpeakerComponent, RadioReceiveEvent>(OnReceiveRadio);
 
-        SubscribeLocalEvent<IntercomComponent, BeforeActivatableUIOpenEvent>(OnBeforeIntercomUiOpen);
+        SubscribeLocalEvent<IntercomComponent, EncryptionChannelsChangedEvent>(OnIntercomEncryptionChannelsChanged);
         SubscribeLocalEvent<IntercomComponent, ToggleIntercomMicMessage>(OnToggleIntercomMic);
         SubscribeLocalEvent<IntercomComponent, ToggleIntercomSpeakerMessage>(OnToggleIntercomSpeaker);
         SubscribeLocalEvent<IntercomComponent, SelectIntercomChannelMessage>(OnSelectIntercomChannel);
@@ -150,18 +147,18 @@ public sealed class RadioDeviceSystem : EntitySystem
         SetSpeakerEnabled(uid, user, !component.Enabled, quiet, component);
     }
 
-    public void SetSpeakerEnabled(EntityUid uid, EntityUid user, bool enabled, bool quiet = false, RadioSpeakerComponent? component = null)
+    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)
+        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, user);
+            _popup.PopupEntity(message, user.Value, user.Value);
         }
 
         _appearance.SetData(uid, RadioDeviceVisuals.Speaker, component.Enabled);
@@ -213,61 +210,74 @@ public sealed class RadioDeviceSystem : EntitySystem
         var nameEv = new TransformSpeakerNameEvent(args.MessageSource, Name(args.MessageSource));
         RaiseLocalEvent(args.MessageSource, nameEv);
 
-        var name = Loc.GetString("speech-name-relay", ("speaker", Name(uid)),
+        var name = Loc.GetString("speech-name-relay",
+            ("speaker", Name(uid)),
             ("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.Whisper, ChatTransmitRange.GhostRangeLimit, nameOverride: name, checkRadioPrefix: false);
     }
 
-    private void OnBeforeIntercomUiOpen(EntityUid uid, IntercomComponent component, BeforeActivatableUIOpenEvent args)
+    private void OnIntercomEncryptionChannelsChanged(Entity<IntercomComponent> ent, ref EncryptionChannelsChangedEvent args)
     {
-        UpdateIntercomUi(uid, component);
+        ent.Comp.SupportedChannels = args.Component.Channels.Select(p => new ProtoId<RadioChannelPrototype>(p)).ToList();
+
+        var channel = args.Component.DefaultChannel;
+        if (ent.Comp.CurrentChannel != null && ent.Comp.SupportedChannels.Contains(ent.Comp.CurrentChannel.Value))
+            channel = ent.Comp.CurrentChannel;
+
+        SetIntercomChannel(ent, channel);
     }
 
-    private void OnToggleIntercomMic(EntityUid uid, IntercomComponent component, ToggleIntercomMicMessage args)
+    private void OnToggleIntercomMic(Entity<IntercomComponent> ent, ref ToggleIntercomMicMessage args)
     {
-        if (component.RequiresPower && !this.IsPowered(uid, EntityManager))
+        if (ent.Comp.RequiresPower && !this.IsPowered(ent, EntityManager))
             return;
 
-        SetMicrophoneEnabled(uid, args.Actor, args.Enabled, true);
-        UpdateIntercomUi(uid, component);
+        SetMicrophoneEnabled(ent, args.Actor, args.Enabled, true);
+        ent.Comp.MicrophoneEnabled = args.Enabled;
+        Dirty(ent);
     }
 
-    private void OnToggleIntercomSpeaker(EntityUid uid, IntercomComponent component, ToggleIntercomSpeakerMessage args)
+    private void OnToggleIntercomSpeaker(Entity<IntercomComponent> ent, ref ToggleIntercomSpeakerMessage args)
     {
-        if (component.RequiresPower && !this.IsPowered(uid, EntityManager))
+        if (ent.Comp.RequiresPower && !this.IsPowered(ent, EntityManager))
             return;
 
-        SetSpeakerEnabled(uid, args.Actor, args.Enabled, true);
-        UpdateIntercomUi(uid, component);
+        SetSpeakerEnabled(ent, args.Actor, args.Enabled, true);
+        ent.Comp.SpeakerEnabled = args.Enabled;
+        Dirty(ent);
     }
 
-    private void OnSelectIntercomChannel(EntityUid uid, IntercomComponent component, SelectIntercomChannelMessage args)
+    private void OnSelectIntercomChannel(Entity<IntercomComponent> ent, ref SelectIntercomChannelMessage args)
     {
-        if (component.RequiresPower && !this.IsPowered(uid, EntityManager))
+        if (ent.Comp.RequiresPower && !this.IsPowered(ent, EntityManager))
             return;
 
-        if (!_protoMan.TryIndex<RadioChannelPrototype>(args.Channel, out _) || !component.SupportedChannels.Contains(args.Channel))
+        if (!_protoMan.HasIndex<RadioChannelPrototype>(args.Channel) || !ent.Comp.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);
+        SetIntercomChannel(ent, args.Channel);
     }
 
-    private void UpdateIntercomUi(EntityUid uid, IntercomComponent component)
+    private void SetIntercomChannel(Entity<IntercomComponent> ent, ProtoId<RadioChannelPrototype>? channel)
     {
-        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.SetUiState(uid, IntercomUiKey.Key, state);
+        ent.Comp.CurrentChannel = channel;
+
+        if (channel == null)
+        {
+            SetSpeakerEnabled(ent, null, false);
+            SetMicrophoneEnabled(ent, null, false);
+            ent.Comp.MicrophoneEnabled = false;
+            ent.Comp.SpeakerEnabled = false;
+            Dirty(ent);
+            return;
+        }
+
+        if (TryComp<RadioMicrophoneComponent>(ent, out var mic))
+            mic.BroadcastChannel = channel;
+        if (TryComp<RadioSpeakerComponent>(ent, out var speaker))
+            speaker.Channels = new(){ channel };
+        Dirty(ent);
     }
 }
index 4341746aafe3493016290fc33bea93c8a7a62a2f..3ad101e62dbd8ff311e8a28704fcdd0631cc5173 100644 (file)
@@ -33,11 +33,15 @@ public sealed class RadioSystem : EntitySystem
     // set used to prevent radio feedback loops.
     private readonly HashSet<string> _messages = new();
 
+    private EntityQuery<TelecomExemptComponent> _exemptQuery;
+
     public override void Initialize()
     {
         base.Initialize();
         SubscribeLocalEvent<IntrinsicRadioReceiverComponent, RadioReceiveEvent>(OnIntrinsicReceive);
         SubscribeLocalEvent<IntrinsicRadioTransmitterComponent, EntitySpokeEvent>(OnIntrinsicSpeak);
+
+        _exemptQuery = GetEntityQuery<TelecomExemptComponent>();
     }
 
     private void OnIntrinsicSpeak(EntityUid uid, IntrinsicRadioTransmitterComponent component, EntitySpokeEvent args)
@@ -121,9 +125,8 @@ public sealed class RadioSystem : EntitySystem
 
         var sourceMapId = Transform(radioSource).MapID;
         var hasActiveServer = HasActiveServer(sourceMapId, channel.ID);
-        var hasMicro = HasComp<RadioMicrophoneComponent>(radioSource);
+        var sourceServerExempt = _exemptQuery.HasComp(radioSource);
 
-        var speakerQuery = GetEntityQuery<RadioSpeakerComponent>();
         var radioQuery = EntityQueryEnumerator<ActiveRadioComponent, TransformComponent>();
         while (canSend && radioQuery.MoveNext(out var receiver, out var radio, out var transform))
         {
@@ -138,7 +141,7 @@ public sealed class RadioSystem : EntitySystem
                 continue;
 
             // don't need telecom server for long range channels or handheld radios and intercoms
-            var needServer = !channel.LongRange && (!hasMicro || !speakerQuery.HasComponent(receiver));
+            var needServer = !channel.LongRange && !sourceServerExempt;
             if (needServer && !hasActiveServer)
                 continue;
 
index be2734ff16849da9459f3144efac1cd2e051a7d5..8d7b87597b101ad89b81e87f1e6fc2a01d37350b 100644 (file)
@@ -1,23 +1,32 @@
 using Robust.Shared.GameStates;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
+using Robust.Shared.Prototypes;
 
 namespace Content.Shared.Radio.Components;
 
 /// <summary>
 /// Handles intercom ui and is authoritative on the channels an intercom can access.
 /// </summary>
-[RegisterComponent, NetworkedComponent]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
 public sealed partial class IntercomComponent : Component
 {
     /// <summary>
-    /// Does this intercom require popwer to function
+    /// Does this intercom require power to function
     /// </summary>
-    [DataField("requiresPower"), ViewVariables(VVAccess.ReadWrite)]
+    [DataField]
     public bool RequiresPower = true;
 
+    [DataField, AutoNetworkedField]
+    public bool SpeakerEnabled;
+
+    [DataField, AutoNetworkedField]
+    public bool MicrophoneEnabled;
+
+    [DataField, AutoNetworkedField]
+    public ProtoId<RadioChannelPrototype>? CurrentChannel;
+
     /// <summary>
     /// The list of radio channel prototypes this intercom can choose between.
     /// </summary>
-    [DataField("supportedChannels", customTypeSerializer: typeof(PrototypeIdListSerializer<RadioChannelPrototype>))]
-    public List<string> SupportedChannels = new();
+    [DataField, AutoNetworkedField]
+    public List<ProtoId<RadioChannelPrototype>> SupportedChannels = new();
 }
diff --git a/Content.Shared/Radio/Components/TelecomExemptComponent.cs b/Content.Shared/Radio/Components/TelecomExemptComponent.cs
new file mode 100644 (file)
index 0000000..7af5c1c
--- /dev/null
@@ -0,0 +1,9 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Radio.Components;
+
+/// <summary>
+/// This is used for a radio that doesn't need a telecom server in order to broadcast.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed partial class TelecomExemptComponent : Component;
index ea07b5f8a5ce96ad906135ce9673b805d7ba3187..cfa553661a394f1418737a72e63226faa53ba6a7 100644 (file)
@@ -31,6 +31,7 @@ public sealed partial class EncryptionKeySystem : EntitySystem
     [Dependency] private readonly SharedContainerSystem _container = default!;
     [Dependency] private readonly SharedAudioSystem _audio = default!;
     [Dependency] private readonly SharedHandsSystem _hands = default!;
+    [Dependency] private readonly SharedWiresSystem _wires = default!;
 
     public override void Initialize()
     {
@@ -150,7 +151,7 @@ public sealed partial class EncryptionKeySystem : EntitySystem
             return;
         }
 
-        if (TryComp<WiresPanelComponent>(uid, out var panel) && !panel.Open)
+        if (!_wires.IsPanelOpen(uid))
         {
             _popup.PopupClient(Loc.GetString("encryption-keys-panel-locked"), uid, args.User);
             return;
@@ -184,8 +185,15 @@ public sealed partial class EncryptionKeySystem : EntitySystem
 
         if (component.Channels.Count > 0)
         {
-            args.PushMarkup(Loc.GetString("examine-encryption-channels-prefix"));
-            AddChannelsExamine(component.Channels, component.DefaultChannel, args, _protoManager, "examine-encryption-channel");
+            using (args.PushGroup(nameof(EncryptionKeyComponent)))
+            {
+                args.PushMarkup(Loc.GetString("examine-encryption-channels-prefix"));
+                AddChannelsExamine(component.Channels,
+                    component.DefaultChannel,
+                    args,
+                    _protoManager,
+                    "examine-encryption-channel");
+            }
         }
     }
 
index 410843312fd28323dd91fb83a22f92a057a6c2ec..f697add8b90c8d8d2e7b2eea0ef01e2cbb956614 100644 (file)
@@ -1,4 +1,5 @@
-using Robust.Shared.Serialization;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization;
 
 namespace Content.Shared.Radio;
 
@@ -8,23 +9,6 @@ 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
 {
index d84766a5fc66691a259b5749ad326c2b0a53a463..7032293eaf6e4e3a035d3ef42a90a4a6bb486709 100644 (file)
@@ -20,6 +20,7 @@ public abstract class SharedWiresSystem : EntitySystem
     {
         base.Initialize();
 
+        SubscribeLocalEvent<WiresPanelComponent, ComponentStartup>(OnStartup);
         SubscribeLocalEvent<WiresPanelComponent, WirePanelDoAfterEvent>(OnPanelDoAfter);
         SubscribeLocalEvent<WiresPanelComponent, InteractUsingEvent>(OnInteractUsing);
         SubscribeLocalEvent<WiresPanelComponent, ExaminedEvent>(OnExamine);
@@ -28,6 +29,11 @@ public abstract class SharedWiresSystem : EntitySystem
         SubscribeLocalEvent<ActivatableUIRequiresPanelComponent, PanelChangedEvent>(OnActivatableUIPanelChanged);
     }
 
+    private void OnStartup(Entity<WiresPanelComponent> ent, ref ComponentStartup args)
+    {
+        UpdateAppearance(ent, ent);
+    }
+
     private void OnPanelDoAfter(EntityUid uid, WiresPanelComponent panel, WirePanelDoAfterEvent args)
     {
         if (args.Cancelled)
index e56e3cd0f73677506682c1c45d7ddc102e875260..63303999c211d436d8437cdd9391bb6d549379f0 100644 (file)
@@ -1,5 +1,6 @@
 intercom-menu-title = Intercom
 intercom-channel-label = Channel:
 intercom-button-text-mic = Mic.
-intercom-button-text-speaker = Speak
+intercom-button-text-speaker = Spkr.
+intercom-options-none = No channels
 intercom-flavor-text-left = Keep lines free of chatter
index 43f84fe404e36d74a2530aaf7e0b45ded2f5c421..77b6cac2d375c74ec41ed28373987b81428066e0 100644 (file)
@@ -4,6 +4,7 @@
   parent: BaseItem
   id: RadioHandheld
   components:
+  - type: TelecomExempt
   - type: RadioMicrophone
     broadcastChannel: Handheld
   - type: RadioSpeaker
@@ -39,4 +40,4 @@
     sprite: Objects/Devices/securityhandy.rsi
   - type: Item
     sprite: Objects/Devices/securityhandy.rsi
-    heldPrefix: walkietalkie
\ No newline at end of file
+    heldPrefix: walkietalkie
index 2cf77d843c50f2741697d62001d889edd403334e..ca1b1b6c40f51ea33cdef655a7a8458f417e6b4f 100644 (file)
@@ -1,5 +1,5 @@
 - type: entity
-  id: Intercom
+  id: BaseIntercom
   name: intercom
   description: An intercom. For when the station just needs to know something.
   abstract: true
@@ -9,6 +9,10 @@
   - type: Electrified
     enabled: false
     usesApcPower: true
+  - type: TelecomExempt
+  - type: EncryptionKeyHolder
+    keySlots: 3
+    keysExtractionMethod: Prying
   - type: RadioMicrophone
     powerRequired: true
     unobstructedRequired: true
   - type: InteractionOutline
   - type: Appearance
   - type: WiresVisuals
+  - type: WiresPanelSecurity
   - type: ContainerFill
     containers:
       board: [ IntercomElectronics ]
   - type: ContainerContainer
     containers:
       board: !type:Container
+      key_slots: !type:Container
   - type: Sprite
     noRot: false
     drawdepth: SmallObjects
@@ -49,7 +55,6 @@
       visible: false
     - state: panel
       map: ["enum.WiresVisualLayers.MaintenancePanel"]
-      shader: unshaded
       visible: false
   - type: Transform
     noRot: false
@@ -61,6 +66,7 @@
   - type: ActivatableUIRequiresPower
   - type: ActivatableUI
     key: enum.IntercomUiKey.Key
+    singleUser: true
   - type: UserInterface
     interfaces:
       enum.IntercomUiKey.Key:
     - Wallmount
 
 - type: entity
-  id: IntercomAssesmbly
+  id: IntercomAssembly
   name: intercom assembly
   description: An intercom. It doesn't seem very helpful right now.
   components:
   - type: Sprite
     drawdepth: SmallObjects
     sprite: Structures/Wallmounts/intercom.rsi
-    state: build
+    layers:
+    - state: build
+    - state: panel
+      visible: false
+      map: [ "wires" ]
+  - type: Appearance
+  - type: GenericVisualizer
+    visuals:
+      enum.ConstructionVisuals.Layer:
+        wires:
+          0: { visible: false }
+          1: { visible: true }
   - type: Construction
     graph: Intercom
     node: assembly
     snap:
     - Wallmount
 
+# this weird inheritance BS exists for construction shitcode
+- type: entity
+  id: IntercomConstructed
+  parent: BaseIntercom
+  suffix: Empty, Panel Open
+  components:
+  - type: Sprite
+    layers:
+    - 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
+    - state: panel
+      map: ["enum.WiresVisualLayers.MaintenancePanel"]
+      visible: true
+  - type: WiresPanel
+    open: true
+
+- type: entity
+  id: Intercom
+  parent: IntercomConstructed
+  suffix: ""
+  components:
+  - type: Sprite
+    layers:
+    - 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
+    - state: panel
+      map: ["enum.WiresVisualLayers.MaintenancePanel"]
+  - type: WiresPanel
+    open: false
+
 - type: entity
   id: IntercomCommon
   parent: Intercom
   suffix: Common
   components:
-  - type: Intercom
-    supportedChannels:
-    - Common
+  - type: ContainerFill
+    containers:
+      board:
+      - IntercomElectronics
+      key_slots:
+      - EncryptionKeyCommon
 
 - type: entity
   id: IntercomCommand
   parent: Intercom
   suffix: Command
   components:
-  - type: Intercom
-    supportedChannels:
-    - Common
-    - Command
+  - type: ContainerFill
+    containers:
+      board:
+      - IntercomElectronics
+      key_slots:
+      - EncryptionKeyCommon
+      - EncryptionKeyCommand
 
 - type: entity
   id: IntercomEngineering
   parent: Intercom
   suffix: Engineering
   components:
-  - type: Intercom
-    supportedChannels:
-    - Common
-    - Engineering
+  - type: ContainerFill
+    containers:
+      board:
+      - IntercomElectronics
+      key_slots:
+      - EncryptionKeyCommon
+      - EncryptionKeyEngineering
 
 - type: entity
   id: IntercomMedical
   parent: Intercom
   suffix: Medical
   components:
-  - type: Intercom
-    supportedChannels:
-    - Common
-    - Medical
+  - type: ContainerFill
+    containers:
+      board:
+      - IntercomElectronics
+      key_slots:
+      - EncryptionKeyCommon
+      - EncryptionKeyMedical
 
 - type: entity
   id: IntercomScience
   parent: Intercom
   suffix: Science
   components:
-  - type: Intercom
-    supportedChannels:
-    - Common
-    - Science
+  - type: ContainerFill
+    containers:
+      board:
+      - IntercomElectronics
+      key_slots:
+      - EncryptionKeyCommon
+      - EncryptionKeyScience
 
 - type: entity
   id: IntercomSecurity
   parent: Intercom
   suffix: Security
+  description: An intercom. It's been reinforced with metal from security helmets, making it a bitch-and-a-half to open.
   components:
-  - type: Intercom
-    supportedChannels:
-    - Common
-    - Security
+  - type: WiresPanel
+    openDelay: 5
+  - type: WiresPanelSecurity
+    examine: wires-panel-component-on-examine-security-level2
+    wiresAccessible: false
+  - type: Construction
+    node: intercomReinforced
+  - type: ContainerFill
+    containers:
+      board:
+      - IntercomElectronics
+      key_slots:
+      - EncryptionKeyCommon
+      - EncryptionKeySecurity
 
 - type: entity
   id: IntercomService
   parent: Intercom
   suffix: Service
   components:
-  - type: Intercom
-    supportedChannels:
-    - Common
-    - Service
+  - type: ContainerFill
+    containers:
+      board:
+      - IntercomElectronics
+      key_slots:
+      - EncryptionKeyCommon
+      - EncryptionKeyService
 
 - type: entity
   id: IntercomSupply
   parent: Intercom
   suffix: Supply
   components:
-  - type: Intercom
-    supportedChannels:
-    - Common
-    - Supply
+  - type: ContainerFill
+    containers:
+      board:
+      - IntercomElectronics
+      key_slots:
+      - EncryptionKeyCommon
+      - EncryptionKeyCargo
 
 - type: entity
   id: IntercomAll
   parent: Intercom
   suffix: All
   components:
-  - type: Intercom
-    supportedChannels:
-    - Common
-    - Command
-    - Engineering
-    - Medical
-    - Science
-    - Security
-    - Service
-    - Supply
+  - type: ContainerFill
+    containers:
+      board:
+      - IntercomElectronics
+      key_slots:
+      - EncryptionKeyCommon
+      - EncryptionKeyStationMaster
index 2247860f892f521b44f8aae14a1463b1082f5e04..ba29d72539a0c2291d1b908d53c012a9213682e3 100644 (file)
         doAfter: 2.0
 
   - node: assembly
-    entity: IntercomAssesmbly
+    entity: IntercomAssembly
     edges:
     - to: wired
       steps:
       - material: Cable
         amount: 2
         doAfter: 1
+      completed:
+      - !type:VisualizerDataInt
+        key: "enum.ConstructionVisuals.Layer"
+        data: 1
     - to: start
       completed:
       - !type:GivePrototype
@@ -29,7 +33,7 @@
         doAfter: 2
 
   - node: wired
-    entity: IntercomAssesmbly
+    entity: IntercomAssembly
     edges:
     - to: electronics
       steps:
@@ -45,6 +49,9 @@
       - !type:GivePrototype
         prototype: CableApcStack1
         amount: 2
+      - !type:VisualizerDataInt
+        key: "enum.ConstructionVisuals.Layer"
+        data: 0
       steps:
       - tool: Cutting
         doAfter: 1
         doAfter: 2
 
   - node: intercom
-    entity: IntercomCommon #TODO: make this work with encryption keys
+    entity: IntercomConstructed
+    doNotReplaceInheritingEntities: true
+    actions:
+    - !type:SetWiresPanelSecurity
+      wiresAccessible: true
     edges:
     - to: wired
       conditions:
       steps:
       - tool: Prying
         doAfter: 1
+    - to: intercomReinforced
+      conditions:
+      - !type:WirePanel
+      steps:
+      - material: Steel
+        amount: 1
+      - tool: Welding
+        doAfter: 1
+
+  - node: intercomReinforced
+    actions:
+    - !type:SetWiresPanelSecurity
+      examine: wires-panel-component-on-examine-security-level2
+      wiresAccessible: false
+    edges:
+    - to: intercom
+      conditions:
+      - !type:WirePanel
+      completed:
+      - !type:GivePrototype
+        prototype: SheetSteel1
+      steps:
+      - tool: Welding
+        doAfter: 5
index 19f2fee18375a914eb3c241d019c508db60beb5c..82c16de7b6a1478de6df6c11c8ec56aa46217ba7 100644 (file)
 # INTERCOM
 - type: construction
   name: intercom
-  id: IntercomAssesmbly
+  id: IntercomAssembly
   graph: Intercom
   startNode: start
   targetNode: intercom
index 787af3f53876b0ceabe9599acf922b1e4f2748f6..a85cbfbecc6aa5f549067703687291f9ea7634a6 100644 (file)
Binary files a/Resources/Textures/Structures/Wallmounts/intercom.rsi/base.png and b/Resources/Textures/Structures/Wallmounts/intercom.rsi/base.png differ
index 0566c70e35cfdc479d4164a4ce0413aace7b9098..962417ccb4d81d45d10de39580760a2931ae3484 100644 (file)
Binary files a/Resources/Textures/Structures/Wallmounts/intercom.rsi/broadcasting.png and b/Resources/Textures/Structures/Wallmounts/intercom.rsi/broadcasting.png differ
index cfd5d5fffa05a8698ea6b43f558766ea817396a3..e8edab0fa02d1783102470f9b37da0cfdada2e67 100644 (file)
Binary files a/Resources/Textures/Structures/Wallmounts/intercom.rsi/build.png and b/Resources/Textures/Structures/Wallmounts/intercom.rsi/build.png differ
index 3bfeb8df5844cecfc419ac23d668a8a800cdf8fa..68f4cd1240b80165a5489ef7287b8bc3b48dc143 100644 (file)
Binary files a/Resources/Textures/Structures/Wallmounts/intercom.rsi/panel.png and b/Resources/Textures/Structures/Wallmounts/intercom.rsi/panel.png differ
index eb09c52fc3a078a9f0995ffac3b3d44ebaee7244..4bcd29d7f4bedbfe0efad7a738265da1ea9ca702 100644 (file)
Binary files a/Resources/Textures/Structures/Wallmounts/intercom.rsi/speaker.png and b/Resources/Textures/Structures/Wallmounts/intercom.rsi/speaker.png differ
index 7b0bb630722bb12089a4a1d54ca9eeeaa7d1b32a..a8fda54fc9332fe037dae35c49093bc5c4650995 100644 (file)
Binary files a/Resources/Textures/Structures/Wallmounts/intercom.rsi/unshaded.png and b/Resources/Textures/Structures/Wallmounts/intercom.rsi/unshaded.png differ
index ef0a5f46b724d44fc28744281e8bc9e3f4b039af..bd42de8f2c5ae8676c06cd644e5bda2d2875e8d5 100644 (file)
@@ -358,3 +358,6 @@ FloorTileItemReinforced: PartRodMetal1
 
 #2024-06-25
 BookChefGaming: BookHowToCookForFortySpaceman
+
+#2024-06-29
+IntercomAssesmbly: IntercomAssembly