diff --git a/Content.Client/Radio/EntitySystems/RadioDeviceSystem.cs b/Content.Client/Radio/EntitySystems/RadioDeviceSystem.cs new file mode 100644 index 0000000000..29d6c635eb --- /dev/null +++ b/Content.Client/Radio/EntitySystems/RadioDeviceSystem.cs @@ -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!; + + /// + public override void Initialize() + { + SubscribeLocalEvent(OnAfterHandleState); + } + + private void OnAfterHandleState(Entity ent, ref AfterAutoHandleStateEvent args) + { + if (_ui.TryGetOpenUi(ent.Owner, IntercomUiKey.Key, out var bui)) + bui.Update(ent); + } +} diff --git a/Content.Client/Radio/Ui/IntercomBoundUserInterface.cs b/Content.Client/Radio/Ui/IntercomBoundUserInterface.cs index abbb1d58ec..7b3e39aa08 100644 --- a/Content.Client/Radio/Ui/IntercomBoundUserInterface.cs +++ b/Content.Client/Radio/Ui/IntercomBoundUserInterface.cs @@ -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(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 ent) { - base.UpdateState(state); - - if (state is not IntercomBoundUIState msg) - return; - - _menu?.Update(msg); + _menu?.Update(ent); } } diff --git a/Content.Client/Radio/Ui/IntercomMenu.xaml.cs b/Content.Client/Radio/Ui/IntercomMenu.xaml.cs index 8b4b38753c..2e08913051 100644 --- a/Content.Client/Radio/Ui/IntercomMenu.xaml.cs +++ b/Content.Client/Radio/Ui/IntercomMenu.xaml.cs @@ -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 _channels = new(); - public IntercomMenu() + public IntercomMenu(Entity 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 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(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); }; } } diff --git a/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs b/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs index 8484fb2336..1258e0b8c7 100644 --- a/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs +++ b/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs @@ -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(OnActivateSpeaker); SubscribeLocalEvent(OnReceiveRadio); - SubscribeLocalEvent(OnBeforeIntercomUiOpen); + SubscribeLocalEvent(OnIntercomEncryptionChannelsChanged); SubscribeLocalEvent(OnToggleIntercomMic); SubscribeLocalEvent(OnToggleIntercomSpeaker); SubscribeLocalEvent(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 ent, ref EncryptionChannelsChangedEvent args) { - UpdateIntercomUi(uid, component); + ent.Comp.SupportedChannels = args.Component.Channels.Select(p => new ProtoId(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 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 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 ent, ref SelectIntercomChannelMessage args) { - if (component.RequiresPower && !this.IsPowered(uid, EntityManager)) + if (ent.Comp.RequiresPower && !this.IsPowered(ent, EntityManager)) return; - if (!_protoMan.TryIndex(args.Channel, out _) || !component.SupportedChannels.Contains(args.Channel)) + if (!_protoMan.HasIndex(args.Channel) || !ent.Comp.SupportedChannels.Contains(args.Channel)) return; - if (TryComp(uid, out var mic)) - mic.BroadcastChannel = args.Channel; - if (TryComp(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 ent, ProtoId? channel) { - var micComp = CompOrNull(uid); - var speakerComp = CompOrNull(uid); + ent.Comp.CurrentChannel = channel; - 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); + if (channel == null) + { + SetSpeakerEnabled(ent, null, false); + SetMicrophoneEnabled(ent, null, false); + ent.Comp.MicrophoneEnabled = false; + ent.Comp.SpeakerEnabled = false; + Dirty(ent); + return; + } + + if (TryComp(ent, out var mic)) + mic.BroadcastChannel = channel; + if (TryComp(ent, out var speaker)) + speaker.Channels = new(){ channel }; + Dirty(ent); } } diff --git a/Content.Server/Radio/EntitySystems/RadioSystem.cs b/Content.Server/Radio/EntitySystems/RadioSystem.cs index 4341746aaf..3ad101e62d 100644 --- a/Content.Server/Radio/EntitySystems/RadioSystem.cs +++ b/Content.Server/Radio/EntitySystems/RadioSystem.cs @@ -33,11 +33,15 @@ public sealed class RadioSystem : EntitySystem // set used to prevent radio feedback loops. private readonly HashSet _messages = new(); + private EntityQuery _exemptQuery; + public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnIntrinsicReceive); SubscribeLocalEvent(OnIntrinsicSpeak); + + _exemptQuery = GetEntityQuery(); } 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(radioSource); + var sourceServerExempt = _exemptQuery.HasComp(radioSource); - var speakerQuery = GetEntityQuery(); var radioQuery = EntityQueryEnumerator(); 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; diff --git a/Content.Shared/Radio/Components/IntercomComponent.cs b/Content.Shared/Radio/Components/IntercomComponent.cs index be2734ff16..8d7b87597b 100644 --- a/Content.Shared/Radio/Components/IntercomComponent.cs +++ b/Content.Shared/Radio/Components/IntercomComponent.cs @@ -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; /// /// Handles intercom ui and is authoritative on the channels an intercom can access. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] public sealed partial class IntercomComponent : Component { /// - /// Does this intercom require popwer to function + /// Does this intercom require power to function /// - [DataField("requiresPower"), ViewVariables(VVAccess.ReadWrite)] + [DataField] public bool RequiresPower = true; + [DataField, AutoNetworkedField] + public bool SpeakerEnabled; + + [DataField, AutoNetworkedField] + public bool MicrophoneEnabled; + + [DataField, AutoNetworkedField] + public ProtoId? CurrentChannel; + /// /// The list of radio channel prototypes this intercom can choose between. /// - [DataField("supportedChannels", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List SupportedChannels = new(); + [DataField, AutoNetworkedField] + public List> SupportedChannels = new(); } diff --git a/Content.Shared/Radio/Components/TelecomExemptComponent.cs b/Content.Shared/Radio/Components/TelecomExemptComponent.cs new file mode 100644 index 0000000000..7af5c1c78c --- /dev/null +++ b/Content.Shared/Radio/Components/TelecomExemptComponent.cs @@ -0,0 +1,9 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Radio.Components; + +/// +/// This is used for a radio that doesn't need a telecom server in order to broadcast. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class TelecomExemptComponent : Component; diff --git a/Content.Shared/Radio/EntitySystems/EncryptionKeySystem.cs b/Content.Shared/Radio/EntitySystems/EncryptionKeySystem.cs index ea07b5f8a5..cfa553661a 100644 --- a/Content.Shared/Radio/EntitySystems/EncryptionKeySystem.cs +++ b/Content.Shared/Radio/EntitySystems/EncryptionKeySystem.cs @@ -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(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"); + } } } diff --git a/Content.Shared/Radio/SharedIntercom.cs b/Content.Shared/Radio/SharedIntercom.cs index 410843312f..f697add8b9 100644 --- a/Content.Shared/Radio/SharedIntercom.cs +++ b/Content.Shared/Radio/SharedIntercom.cs @@ -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 AvailableChannels; - public string SelectedChannel; - - public IntercomBoundUIState(bool micEnabled, bool speakerEnabled, List availableChannels, string selectedChannel) - { - MicEnabled = micEnabled; - SpeakerEnabled = speakerEnabled; - AvailableChannels = availableChannels; - SelectedChannel = selectedChannel; - } -} - [Serializable, NetSerializable] public sealed class ToggleIntercomMicMessage : BoundUserInterfaceMessage { diff --git a/Content.Shared/Wires/SharedWiresSystem.cs b/Content.Shared/Wires/SharedWiresSystem.cs index d84766a5fc..7032293eaf 100644 --- a/Content.Shared/Wires/SharedWiresSystem.cs +++ b/Content.Shared/Wires/SharedWiresSystem.cs @@ -20,6 +20,7 @@ public abstract class SharedWiresSystem : EntitySystem { base.Initialize(); + SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnPanelDoAfter); SubscribeLocalEvent(OnInteractUsing); SubscribeLocalEvent(OnExamine); @@ -28,6 +29,11 @@ public abstract class SharedWiresSystem : EntitySystem SubscribeLocalEvent(OnActivatableUIPanelChanged); } + private void OnStartup(Entity ent, ref ComponentStartup args) + { + UpdateAppearance(ent, ent); + } + private void OnPanelDoAfter(EntityUid uid, WiresPanelComponent panel, WirePanelDoAfterEvent args) { if (args.Cancelled) diff --git a/Resources/Locale/en-US/radio/components/intercom.ftl b/Resources/Locale/en-US/radio/components/intercom.ftl index e56e3cd0f7..63303999c2 100644 --- a/Resources/Locale/en-US/radio/components/intercom.ftl +++ b/Resources/Locale/en-US/radio/components/intercom.ftl @@ -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 diff --git a/Resources/Prototypes/Entities/Objects/Devices/radio.yml b/Resources/Prototypes/Entities/Objects/Devices/radio.yml index 43f84fe404..77b6cac2d3 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/radio.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/radio.yml @@ -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 diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml index 2cf77d843c..ca1b1b6c40 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml @@ -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 @@ -24,12 +28,14 @@ - 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: @@ -116,7 +122,7 @@ - Wallmount - type: entity - id: IntercomAssesmbly + id: IntercomAssembly name: intercom assembly description: An intercom. It doesn't seem very helpful right now. components: @@ -126,7 +132,18 @@ - 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 @@ -137,97 +154,176 @@ 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 diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/utilities/intercom.yml b/Resources/Prototypes/Recipes/Construction/Graphs/utilities/intercom.yml index 2247860f89..ba29d72539 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/utilities/intercom.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/utilities/intercom.yml @@ -11,13 +11,17 @@ 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 @@ -57,7 +64,11 @@ 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: @@ -72,3 +83,27 @@ 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 diff --git a/Resources/Prototypes/Recipes/Construction/utilities.yml b/Resources/Prototypes/Recipes/Construction/utilities.yml index 19f2fee183..82c16de7b6 100644 --- a/Resources/Prototypes/Recipes/Construction/utilities.yml +++ b/Resources/Prototypes/Recipes/Construction/utilities.yml @@ -790,7 +790,7 @@ # INTERCOM - type: construction name: intercom - id: IntercomAssesmbly + id: IntercomAssembly graph: Intercom startNode: start targetNode: intercom diff --git a/Resources/Textures/Structures/Wallmounts/intercom.rsi/base.png b/Resources/Textures/Structures/Wallmounts/intercom.rsi/base.png index 787af3f538..a85cbfbecc 100644 Binary files a/Resources/Textures/Structures/Wallmounts/intercom.rsi/base.png and b/Resources/Textures/Structures/Wallmounts/intercom.rsi/base.png differ diff --git a/Resources/Textures/Structures/Wallmounts/intercom.rsi/broadcasting.png b/Resources/Textures/Structures/Wallmounts/intercom.rsi/broadcasting.png index 0566c70e35..962417ccb4 100644 Binary files a/Resources/Textures/Structures/Wallmounts/intercom.rsi/broadcasting.png and b/Resources/Textures/Structures/Wallmounts/intercom.rsi/broadcasting.png differ diff --git a/Resources/Textures/Structures/Wallmounts/intercom.rsi/build.png b/Resources/Textures/Structures/Wallmounts/intercom.rsi/build.png index cfd5d5fffa..e8edab0fa0 100644 Binary files a/Resources/Textures/Structures/Wallmounts/intercom.rsi/build.png and b/Resources/Textures/Structures/Wallmounts/intercom.rsi/build.png differ diff --git a/Resources/Textures/Structures/Wallmounts/intercom.rsi/panel.png b/Resources/Textures/Structures/Wallmounts/intercom.rsi/panel.png index 3bfeb8df58..68f4cd1240 100644 Binary files a/Resources/Textures/Structures/Wallmounts/intercom.rsi/panel.png and b/Resources/Textures/Structures/Wallmounts/intercom.rsi/panel.png differ diff --git a/Resources/Textures/Structures/Wallmounts/intercom.rsi/speaker.png b/Resources/Textures/Structures/Wallmounts/intercom.rsi/speaker.png index eb09c52fc3..4bcd29d7f4 100644 Binary files a/Resources/Textures/Structures/Wallmounts/intercom.rsi/speaker.png and b/Resources/Textures/Structures/Wallmounts/intercom.rsi/speaker.png differ diff --git a/Resources/Textures/Structures/Wallmounts/intercom.rsi/unshaded.png b/Resources/Textures/Structures/Wallmounts/intercom.rsi/unshaded.png index 7b0bb63072..a8fda54fc9 100644 Binary files a/Resources/Textures/Structures/Wallmounts/intercom.rsi/unshaded.png and b/Resources/Textures/Structures/Wallmounts/intercom.rsi/unshaded.png differ diff --git a/Resources/migration.yml b/Resources/migration.yml index ef0a5f46b7..bd42de8f2c 100644 --- a/Resources/migration.yml +++ b/Resources/migration.yml @@ -358,3 +358,6 @@ FloorTileItemReinforced: PartRodMetal1 #2024-06-25 BookChefGaming: BookHowToCookForFortySpaceman + +#2024-06-29 +IntercomAssesmbly: IntercomAssembly