diff --git a/Content.Server/Chat/Systems/ChatSystem.Radio.cs b/Content.Server/Chat/Systems/ChatSystem.Radio.cs index 172ac780fd..1a18ac4bb5 100644 --- a/Content.Server/Chat/Systems/ChatSystem.Radio.cs +++ b/Content.Server/Chat/Systems/ChatSystem.Radio.cs @@ -67,8 +67,8 @@ public sealed partial class ChatSystem // Redirect to defaultChannel of headsetComp if it goes to "h" channel code after making sure defaultChannel exists if (message[1] == 'h' && _headsetComponent != null - && _headsetComponent.defaultChannel != null - && _prototypeManager.TryIndex(_headsetComponent.defaultChannel, out RadioChannelPrototype? protoDefaultChannel)) + && _headsetComponent.DefaultChannel != null + && _prototypeManager.TryIndex(_headsetComponent.DefaultChannel, out RadioChannelPrototype? protoDefaultChannel)) { // Set Channel to headset defaultChannel channel = protoDefaultChannel; diff --git a/Content.Server/Radio/Components/HeadsetComponent.cs b/Content.Server/Radio/Components/HeadsetComponent.cs index caf09fe875..fb9ee9a247 100644 --- a/Content.Server/Radio/Components/HeadsetComponent.cs +++ b/Content.Server/Radio/Components/HeadsetComponent.cs @@ -1,11 +1,12 @@ using Content.Server.Radio.EntitySystems; using Content.Shared.Inventory; using Content.Shared.Radio; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set; +using Content.Shared.Tools; +using Robust.Shared.Audio; +using Robust.Shared.Containers; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Server.Radio.Components; - /// /// This component relays radio messages to the parent entity's chat when equipped. /// @@ -13,17 +14,52 @@ namespace Content.Server.Radio.Components; [Access(typeof(HeadsetSystem))] public sealed class HeadsetComponent : Component { - [DataField("channels", customTypeSerializer: typeof(PrototypeIdHashSetSerializer))] - public readonly HashSet Channels = new() { "Common" }; + /// + /// This variable indicates locked state of encryption keys, allowing or prohibiting inserting and removing of encryption keys from headset. + /// true => User are able to remove encryption keys with tool mentioned in KeysExtractionMethod, and put encryption keys in headset. + /// false => encryption keys are locked in headset, they can't be properly removed or added. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("isKeysUnlocked")] + public bool IsKeysUnlocked = true; + /// + /// Shows which tool a person should use to extract the encryption keys from the headset. + /// default "Screwing" + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("keysExtractionMethod", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string KeysExtractionMethod = "Screwing"; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("keySlots")] + public int KeySlots = 2; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("keyExtractionSound")] + public SoundSpecifier KeyExtractionSound = new SoundPathSpecifier("/Audio/Items/pistol_magout.ogg"); + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("keyInsertionSound")] + public SoundSpecifier KeyInsertionSound = new SoundPathSpecifier("/Audio/Items/pistol_magin.ogg"); + + [ViewVariables] + public Container KeyContainer = default!; + public const string KeyContainerName = "key_slots"; + + [ViewVariables] + public HashSet Channels = new(); // Maybe make the defaultChannel an actual channel type some day, and use that for parsing messages // [DataField("defaultChannel", customTypeSerializer: typeof(PrototypeIdHashSetSerializer))] // public readonly HashSet defaultChannel = new(); - - - [DataField("defaultChannel", customTypeSerializer: typeof(PrototypeIdSerializer))] - public readonly string? defaultChannel; + /// + /// This variable defines what channel will be used with using ":h" (department channel prefix). + /// Headset read DefaultChannel of first encryption key installed. + /// Do not change this variable from headset or VV, better change encryption keys and UpdateDefaultChannel. + /// + [ViewVariables(VVAccess.ReadOnly)] + public string? DefaultChannel; [DataField("enabled")] public bool Enabled = true; diff --git a/Content.Server/Radio/EntitySystems/HeadsetSystem.cs b/Content.Server/Radio/EntitySystems/HeadsetSystem.cs index f8ae3503e2..f4b0585a30 100644 --- a/Content.Server/Radio/EntitySystems/HeadsetSystem.cs +++ b/Content.Server/Radio/EntitySystems/HeadsetSystem.cs @@ -1,11 +1,18 @@ using Content.Server.Chat.Systems; -using Content.Server.Radio.Components; +using Content.Server.Popups; +using Content.Server.Tools; +using Content.Shared.Tools.Components; using Content.Shared.Examine; +using Content.Shared.Interaction; using Content.Shared.Inventory.Events; using Content.Shared.Radio; +using Content.Server.Radio.Components; using Robust.Server.GameObjects; +using Robust.Shared.Containers; using Robust.Shared.Network; using Robust.Shared.Prototypes; +using System.Linq; +using Robust.Shared.Profiling; namespace Content.Server.Radio.EntitySystems; @@ -14,6 +21,10 @@ public sealed class HeadsetSystem : EntitySystem [Dependency] private readonly IPrototypeManager _protoManager = default!; [Dependency] private readonly INetManager _netMan = default!; [Dependency] private readonly RadioSystem _radio = default!; + [Dependency] private readonly ToolSystem _toolSystem = default!; + [Dependency] private readonly PopupSystem _popupSystem = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; public override void Initialize() { @@ -23,6 +34,10 @@ public sealed class HeadsetSystem : EntitySystem SubscribeLocalEvent(OnGotEquipped); SubscribeLocalEvent(OnGotUnequipped); SubscribeLocalEvent(OnSpeak); + + SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent(OnInteractUsing); + SubscribeLocalEvent(OnContainerInserted); } private void OnSpeak(EntityUid uid, WearingHeadsetComponent component, EntitySpokeEvent args) @@ -43,10 +58,15 @@ public sealed class HeadsetSystem : EntitySystem if (component.IsEquipped && component.Enabled) { EnsureComp(args.Equipee).Headset = uid; - EnsureComp(uid).Channels.UnionWith(component.Channels); + PushRadioChannelsToOwner(uid, component, EnsureComp(uid)); } } + private void PushRadioChannelsToOwner(EntityUid uid, HeadsetComponent component, ActiveRadioComponent activeRadio) + { + activeRadio.Channels.UnionWith(component.Channels); + } + private void OnGotUnequipped(EntityUid uid, HeadsetComponent component, GotUnequippedEvent args) { component.IsEquipped = false; @@ -86,21 +106,127 @@ public sealed class HeadsetSystem : EntitySystem { if (!args.IsInDetailsRange) return; - - args.PushMarkup(Loc.GetString("examine-headset")); - - foreach (var id in component.Channels) + if (component.KeyContainer.ContainedEntities.Count == 0) { - if (id == "Common") continue; - - var proto = _protoManager.Index(id); - args.PushMarkup(Loc.GetString("examine-headset-channel", - ("color", proto.Color), - ("key", proto.KeyCode), - ("id", proto.LocalizedName), - ("freq", proto.Frequency))); + args.PushMarkup(Loc.GetString("examine-headset-no-keys")); + return; } + else if (component.Channels.Count > 0) + { + args.PushMarkup(Loc.GetString("examine-headset-channels-prefix")); + EncryptionKeySystem.GetChannelsExamine(component.Channels, args, _protoManager, "examine-headset-channel"); + args.PushMarkup(Loc.GetString("examine-headset-chat-prefix", ("prefix", ":h"))); + if (component.DefaultChannel != null) + { + var proto = _protoManager.Index(component.DefaultChannel); + args.PushMarkup(Loc.GetString("examine-headset-default-channel", ("channel", component.DefaultChannel), ("color", proto.Color))); + } + } + } - args.PushMarkup(Loc.GetString("examine-headset-chat-prefix", ("prefix", ";"))); + private void OnStartup(EntityUid uid, HeadsetComponent component, ComponentStartup args) + { + component.KeyContainer = _container.EnsureContainer(uid, HeadsetComponent.KeyContainerName); + } + + private bool InstallKey(HeadsetComponent component, EntityUid key, EncryptionKeyComponent keyComponent) + { + if (component.KeyContainer.Insert(key)) + { + UploadChannelsFromKey(component, keyComponent); + return true; + } + return false; + } + + private void UploadChannelsFromKey(HeadsetComponent component, EncryptionKeyComponent key) + { + foreach (var j in key.Channels) + component.Channels.Add(j); + } + + public void RecalculateChannels(HeadsetComponent component) + { + component.Channels.Clear(); + foreach (EntityUid i in component.KeyContainer.ContainedEntities) + { + if (TryComp(i, out var key)) + { + UploadChannelsFromKey(component, key); + } + } + } + + private void OnInteractUsing(EntityUid uid, HeadsetComponent component, InteractUsingEvent args) + { + if (!TryComp(uid, out var storage)) + return; + if(!component.IsKeysUnlocked) + { + _popupSystem.PopupEntity(Loc.GetString("headset-encryption-keys-are-locked"), uid, args.User); + return; + } + if (TryComp(args.Used, out var key)) + { + if (component.KeySlots > component.KeyContainer.ContainedEntities.Count) + { + if (InstallKey(component, args.Used, key)) + { + _popupSystem.PopupEntity(Loc.GetString("headset-encryption-key-successfully-installed"), uid, args.User); + _audio.PlayPvs(component.KeyInsertionSound, args.Target); + } + } + else + { + _popupSystem.PopupEntity(Loc.GetString("headset-encryption-key-slots-already-full"), uid, args.User); + } + } + if (TryComp(args.Used, out var tool)) + { + if (component.KeyContainer.ContainedEntities.Count > 0) + { + if (_toolSystem.UseTool( + args.Used, args.User, uid, + 0f, 0f, new String[] { component.KeysExtractionMethod }, + doAfterCompleteEvent: null, toolComponent: tool) + ) + { + var contained = component.KeyContainer.ContainedEntities.ToArray(); + foreach (var i in contained) + component.KeyContainer.Remove(i); + component.Channels.Clear(); + UpdateDefaultChannel(component); + _popupSystem.PopupEntity(Loc.GetString("headset-encryption-keys-all-extracted"), uid, args.User); + _audio.PlayPvs(component.KeyExtractionSound, args.Target); + } + } + else + { + _popupSystem.PopupEntity(Loc.GetString("headset-encryption-keys-no-keys"), uid, args.User); + } + } + } + + private void UpdateDefaultChannel(HeadsetComponent component) + { + if (component.KeyContainer.ContainedEntities.Count >= 1) + component.DefaultChannel = EnsureComp(component.KeyContainer.ContainedEntities[0])?.DefaultChannel; + else + component.DefaultChannel = null; + } + + private void OnContainerInserted(EntityUid uid, HeadsetComponent component, EntInsertedIntoContainerMessage args) + { + if (args.Container.ID != HeadsetComponent.KeyContainerName) + { + return; + } + if (TryComp(args.Entity, out var added)) + { + UpdateDefaultChannel(component); + UploadChannelsFromKey(component, added); + PushRadioChannelsToOwner(uid, component, EnsureComp(uid)); + } + return; } } diff --git a/Content.Shared/Radio/EncryptionKeyComponent.cs b/Content.Shared/Radio/EncryptionKeyComponent.cs new file mode 100644 index 0000000000..9fcd649a40 --- /dev/null +++ b/Content.Shared/Radio/EncryptionKeyComponent.cs @@ -0,0 +1,23 @@ +using Content.Shared.Radio; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set; + +namespace Content.Server.Radio.Components; +/// +/// This component is currently used for providing access to channels for "HeadsetComponent"s. +/// It should be used for intercoms and other radios in future. +/// +[RegisterComponent] +public sealed class EncryptionKeyComponent : Component +{ + [DataField("channels", customTypeSerializer: typeof(PrototypeIdHashSetSerializer))] + public HashSet Channels = new(); + + + /// + /// This variable defines what channel will be used with using ":h" (department channel prefix). + /// Headset read DefaultChannel of first encryption key installed. + /// + [DataField("defaultChannel", customTypeSerializer: typeof(PrototypeIdSerializer))] + public readonly string? DefaultChannel; +} diff --git a/Content.Shared/Radio/EncryptionKeySystem.cs b/Content.Shared/Radio/EncryptionKeySystem.cs new file mode 100644 index 0000000000..37bd5c7670 --- /dev/null +++ b/Content.Shared/Radio/EncryptionKeySystem.cs @@ -0,0 +1,55 @@ +using Content.Server.Radio.Components; +using Content.Shared.Examine; +using Content.Shared.Radio; +using Robust.Shared.Prototypes; + +namespace Content.Server.Radio.EntitySystems; + +public sealed class EncryptionKeySystem : EntitySystem +{ + [Dependency] private readonly IPrototypeManager _protoManager = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnExamined); + } + + private void OnExamined(EntityUid uid, EncryptionKeyComponent component, ExaminedEvent args) + { + if (!args.IsInDetailsRange) + return; + if(component.Channels.Count > 0) + { + args.PushMarkup(Loc.GetString("examine-encryption-key-channels-prefix")); + EncryptionKeySystem.GetChannelsExamine(component.Channels, args, _protoManager, "examine-headset-channel"); + if (component.DefaultChannel != null) + { + var proto = _protoManager.Index(component.DefaultChannel); + args.PushMarkup(Loc.GetString("examine-encryption-key-default-channel", ("channel", component.DefaultChannel), ("color", proto.Color))); + } + } + } + + /// + /// A static method for formating list of radio channels for examine events. + /// + /// HashSet of channels in headset, encryptionkey or etc. + /// IPrototypeManager for getting prototypes of channels with their variables. + /// String that provide id of pattern in .ftl files to format channel with variables of it. + public static void GetChannelsExamine(HashSet channels, ExaminedEvent examineEvent, IPrototypeManager protoManager, string channelFTLPattern) + { + foreach (var id in channels) + { + var proto = protoManager.Index(id); + string keyCode = "" + proto.KeyCode; + if (id != "Common") + keyCode = ":" + keyCode; + examineEvent.PushMarkup(Loc.GetString(channelFTLPattern, + ("color", proto.Color), + ("key", keyCode), + ("id", proto.LocalizedName), + ("freq", proto.Frequency))); + } + } +} diff --git a/Resources/Locale/en-US/headset/headset-component.ftl b/Resources/Locale/en-US/headset/headset-component.ftl index 44795011ef..bf68eb4260 100644 --- a/Resources/Locale/en-US/headset/headset-component.ftl +++ b/Resources/Locale/en-US/headset/headset-component.ftl @@ -1,12 +1,22 @@ # Chat window radio wrap (prefix and postfix) chat-radio-message-wrap = [color={$color}]{$channel} {$name} says: "{$message}"[/color] +headset-encryption-key-successfully-installed = You put the key into the headset. +headset-encryption-key-slots-already-full = There is no place for another key. +headset-encryption-keys-all-extracted = You pop out the encryption keys from the headset! +headset-encryption-keys-no-keys = This headset has no encryption keys! +headset-encryption-keys-are-locked = The headset's key slots are locked, you cannot add or remove any keys. + +examine-encryption-key-channels-prefix = It is providing these frequencies to the headset: + examine-radio-frequency = It's set to broadcast over the {$frequency} frequency. -examine-headset = A small screen on the headset displays the following available frequencies: -examine-headset-channel = [color={$color}]:{$key} for {$id} ({$freq})[/color] - -examine-headset-chat-prefix = Use {$prefix} for the currently tuned frequency. +examine-headset-channels-prefix = A small screen on the headset displays the following available frequencies: +examine-headset-channel = [color={$color}]{$key} for {$id} ({$freq})[/color] +examine-headset-no-keys = It seems broken. There are no encryption keys in it. +examine-headset-chat-prefix = Use this {$prefix} for your department's frequency. +examine-headset-default-channel = It's indicates that default channel of this headset is [color={$color}]{$channel}[/color]. +examine-encryption-key-default-channel = It's seems like [color={$color}]{$channel}[/color] is a default channel. chat-radio-common = Common chat-radio-centcom = CentCom diff --git a/Resources/Locale/en-US/store/uplink-catalog.ftl b/Resources/Locale/en-US/store/uplink-catalog.ftl index 1e14c889a6..28fa900bc8 100644 --- a/Resources/Locale/en-US/store/uplink-catalog.ftl +++ b/Resources/Locale/en-US/store/uplink-catalog.ftl @@ -76,7 +76,10 @@ uplink-stealth-box-name = Stealth Box uplink-stealth-box-desc = A box outfitted with stealth technology, sneak around with this and don't move too fast now! uplink-headset-name = Syndicate Over-ear Headset -uplink-headset-desc = A headset that allows you to listen in on departmental channels, or contact other traitors. +uplink-headset-desc = A headset that allows you to communicate with other syndicate operatives. Has 4 slots for encryption keys. + +uplink-encryption-key-name = Syndicate Encryption Key +uplink-encryption-key-desc = An encryption key for access to the secret frequency of our special agents. No one will know about your special channel with friends... or rivals. uplink-hypopen-name = Hypopen uplink-hypopen-desc = A chemical hypospray disguised as a pen, capable of instantly injecting up to 15u of reagents. Starts empty. diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index 811e76d66e..5aae9b79ba 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -268,16 +268,26 @@ categories: - UplinkUtility -#TODO: Increase the price of this to 4-5/remove it when we get encrpytion keys +#TODO: Increase the price to 4 when flashbang prof. - type: listing id: UplinkHeadset name: uplink-headset-name description: uplink-headset-desc productEntity: ClothingHeadsetAltSyndicate cost: - Telecrystal: 2 # next step is adding encryption keys + Telecrystal: 4 categories: - - UplinkUtility + - UplinkUtility + +- type: listing + id: UplinkHeadsetEncryptionKey + name: uplink-encryption-key-name + description: uplink-encryption-key-desc + productEntity: EncryptionKeySyndie + cost: + Telecrystal: 2 + categories: + - UplinkUtility - type: listing id: UplinkHypopen diff --git a/Resources/Prototypes/Entities/Clothing/Ears/headsets.yml b/Resources/Prototypes/Entities/Clothing/Ears/headsets.yml index 44448d298f..8dc10add35 100644 --- a/Resources/Prototypes/Entities/Clothing/Ears/headsets.yml +++ b/Resources/Prototypes/Entities/Clothing/Ears/headsets.yml @@ -5,7 +5,15 @@ name: headset description: An updated, modular intercom that fits over the head. Takes encryption keys. components: + - type: ContainerContainer + containers: + key_slots: !type:Container + - type: ContainerFill + containers: + key_slots: + - EncryptionKeyCommon - type: Headset + keysExtractionMethod: Screwing - type: Sprite state: icon - type: Clothing @@ -13,38 +21,50 @@ - ears sprite: Clothing/Ears/Headsets/base.rsi +- type: entity + parent: ClothingHeadset + id: ClothingHeadsetGrey + name: passenger headset + components: + - type: Sprite + sprite: Clothing/Ears/Headsets/base.rsi + - type: entity parent: ClothingHeadset id: ClothingHeadsetCargo name: cargo headset description: A headset used by supply employees. components: - - type: Headset - channels: - - Common - - Supply - defaultChannel: Supply + - type: ContainerFill + containers: + key_slots: + - EncryptionKeyCargo - type: Sprite sprite: Clothing/Ears/Headsets/cargo.rsi - type: Clothing sprite: Clothing/Ears/Headsets/cargo.rsi - type: entity - parent: ClothingHeadset + parent: ClothingHeadsetCargo + id: ClothingHeadsetMining + name: mining headset + description: Headset used by shaft miners. + components: + - type: Sprite + sprite: Clothing/Ears/Headsets/mining.rsi + - type: Clothing + sprite: Clothing/Ears/Headsets/mining.rsi + +- type: entity + parent: ClothingHeadsetCargo id: ClothingHeadsetQM name: qm headset description: A headset used by the quartermaster. components: - - type: Headset - channels: - - Command - - Common - - Supply - defaultChannel: Supply - - type: Sprite - sprite: Clothing/Ears/Headsets/cargo.rsi - - type: Clothing - sprite: Clothing/Ears/Headsets/cargo.rsi + - type: ContainerFill + containers: + key_slots: + - EncryptionKeyQM - type: entity parent: ClothingHeadset @@ -52,18 +72,10 @@ name: CentCom headset description: A headset used by the upper echelons of Nanotrasen. components: - - type: Headset - channels: - - Common - - Command - - CentCom - - Engineering - - Medical - - Science - - Security - - Service - - Supply - defaultChannel: CentCom + - type: ContainerFill + containers: + key_slots: + - EncryptionKeyCentCom - type: Sprite sprite: Clothing/Ears/Headsets/centcom.rsi - type: Clothing @@ -75,17 +87,10 @@ name: command headset description: A headset with a commanding channel. components: - - type: Headset - channels: - - Common - - Command - - Engineering - - Medical - - Science - - Security - - Service - - Supply - defaultChannel: Command + - type: ContainerFill + containers: + key_slots: + - EncryptionKeyCommand - type: Sprite sprite: Clothing/Ears/Headsets/command.rsi - type: Clothing @@ -97,32 +102,25 @@ name: engineering headset description: A headset for engineers to chat while the station burns around them. components: - - type: Headset - channels: - - Common - - Engineering - defaultChannel: Engineering + - type: ContainerFill + containers: + key_slots: + - EncryptionKeyEngineering - type: Sprite sprite: Clothing/Ears/Headsets/engineering.rsi - type: Clothing sprite: Clothing/Ears/Headsets/engineering.rsi - type: entity - parent: ClothingHeadset + parent: ClothingHeadsetEngineering id: ClothingHeadsetCE name: ce headset description: A headset for the chief engineer to ignore all emergency calls on. components: - - type: Headset - channels: - - Command - - Common - - Engineering - defaultChannel: Engineering - - type: Sprite - sprite: Clothing/Ears/Headsets/engineering.rsi - - type: Clothing - sprite: Clothing/Ears/Headsets/engineering.rsi + - type: ContainerFill + containers: + key_slots: + - EncryptionKeyCE - type: entity parent: ClothingHeadset @@ -130,97 +128,70 @@ name: medical headset description: A headset for the trained staff of the medbay. components: - - type: Headset - channels: - - Common - - Medical - defaultChannel: Medical + - type: ContainerFill + containers: + key_slots: + - EncryptionKeyMedical - type: Sprite sprite: Clothing/Ears/Headsets/medical.rsi - type: Clothing sprite: Clothing/Ears/Headsets/medical.rsi -- type: entity - parent: ClothingHeadset - id: ClothingHeadsetMedicalScience - name: medical research headset - description: A headset that is a result of the mating between medical and science. - components: - - type: Headset - channels: - - Common - - Medical - - Science - defaultChannel: Science - - type: Sprite - sprite: Clothing/Ears/Headsets/medicalscience.rsi - - type: Clothing - sprite: Clothing/Ears/Headsets/medicalscience.rsi - -- type: entity - parent: ClothingHeadset - id: ClothingHeadsetMining - name: mining headset - description: Headset used by shaft miners. - components: - - type: Headset - channels: - - Common - - Supply - defaultChannel: Supply - - type: Sprite - sprite: Clothing/Ears/Headsets/mining.rsi - - type: Clothing - sprite: Clothing/Ears/Headsets/mining.rsi - -- type: entity - parent: ClothingHeadset - id: ClothingHeadsetRobotics - name: robotics headset - description: Made specifically for the roboticists, who cannot decide between departments. - components: - - type: Headset - channels: - - Common - - Science - defaultChannel: Science - - type: Sprite - sprite: Clothing/Ears/Headsets/robotics.rsi - - type: Clothing - sprite: Clothing/Ears/Headsets/robotics.rsi - - type: entity parent: ClothingHeadset id: ClothingHeadsetScience name: science headset description: A sciency headset. Like usual. components: - - type: Headset - channels: - - Common - - Science - defaultChannel: Science + - type: ContainerFill + containers: + key_slots: + - EncryptionKeyScience - type: Sprite sprite: Clothing/Ears/Headsets/science.rsi - type: Clothing sprite: Clothing/Ears/Headsets/science.rsi - type: entity - parent: ClothingHeadset + parent: ClothingHeadsetScience + id: ClothingHeadsetMedicalScience + name: medical research headset + description: A headset that is a result of the mating between medical and science. + components: + - type: ContainerFill + containers: + key_slots: + - EncryptionKeyMedicalScience + - type: Sprite + sprite: Clothing/Ears/Headsets/medicalscience.rsi + - type: Clothing + sprite: Clothing/Ears/Headsets/medicalscience.rsi + +- type: entity + parent: ClothingHeadsetScience + id: ClothingHeadsetRobotics + name: robotics headset + description: Made specifically for the roboticists, who cannot decide between departments. + components: + - type: ContainerFill + containers: + key_slots: + - EncryptionKeyRobo + - type: Sprite + sprite: Clothing/Ears/Headsets/robotics.rsi + - type: Clothing + sprite: Clothing/Ears/Headsets/robotics.rsi + +- type: entity + parent: ClothingHeadsetScience id: ClothingHeadsetRD name: rd headset description: Lamarr used to love chewing on this... components: - - type: Headset - channels: - - Command - - Common - - Science - defaultChannel: Science - - type: Sprite - sprite: Clothing/Ears/Headsets/science.rsi - - type: Clothing - sprite: Clothing/Ears/Headsets/science.rsi + - type: ContainerFill + containers: + key_slots: + - EncryptionKeyRD - type: entity parent: ClothingHeadset @@ -228,11 +199,10 @@ name: security headset description: This is used by your elite security force. components: - - type: Headset - channels: - - Common - - Security - defaultChannel: Security + - type: ContainerFill + containers: + key_slots: + - EncryptionKeySecurity - type: Sprite sprite: Clothing/Ears/Headsets/security.rsi - type: Clothing @@ -244,25 +214,12 @@ name: service headset description: Headset used by the service staff, tasked with keeping the station full, happy and clean. components: - - type: Headset - channels: - - Common - - Service - defaultChannel: Service + - type: ContainerFill + containers: + key_slots: + - EncryptionKeyService - type: Sprite sprite: Clothing/Ears/Headsets/service.rsi - type: Clothing sprite: Clothing/Ears/Headsets/service.rsi -- type: entity - parent: ClothingHeadset - id: ClothingHeadsetGrey - name: passenger headset - description: An updated, modular intercom that fits over the head. Takes encryption keys. - components: - - type: Headset - channels: - - Common - defaultChannel: Common - - type: Sprite - sprite: Clothing/Ears/Headsets/base.rsi diff --git a/Resources/Prototypes/Entities/Clothing/Ears/headsets_alt.yml b/Resources/Prototypes/Entities/Clothing/Ears/headsets_alt.yml index d4f603941e..85770cab21 100644 --- a/Resources/Prototypes/Entities/Clothing/Ears/headsets_alt.yml +++ b/Resources/Prototypes/Entities/Clothing/Ears/headsets_alt.yml @@ -1,56 +1,52 @@ - type: entity abstract: true - parent: Clothing + parent: ClothingHeadset id: ClothingHeadsetAlt name: headset description: An updated, modular intercom that fits over the head. Takes encryption keys. components: - - type: Headset - type: Sprite state: icon_alt - type: Clothing equippedPrefix: alt - slots: - - ears + +- type: entity + parent: ClothingHeadsetAlt + id: ClothingHeadsetAltCargo + name: quartermaster's over-ear headset + components: + - type: ContainerFill + containers: + key_slots: + - EncryptionKeyQM + - type: Sprite + sprite: Clothing/Ears/Headsets/cargo.rsi + - type: Clothing + sprite: Clothing/Ears/Headsets/cargo.rsi - type: entity parent: ClothingHeadsetAlt id: ClothingHeadsetAltCentCom name: CentCom over-ear headset components: - - type: Headset - channels: - - Common - - Command - - CentCom - - Engineering - - Medical - - Science - - Security - - Service - - Supply - defaultChannel: CentCom - - type: Sprite - sprite: Clothing/Ears/Headsets/centcom.rsi - - type: Clothing - sprite: Clothing/Ears/Headsets/centcom.rsi + - type: ContainerFill + containers: + key_slots: + - EncryptionKeyCentCom + - type: Sprite + sprite: Clothing/Ears/Headsets/centcom.rsi + - type: Clothing + sprite: Clothing/Ears/Headsets/centcom.rsi - type: entity parent: ClothingHeadsetAlt id: ClothingHeadsetAltCommand name: command over-ear headset components: - - type: Headset - channels: - - Common - - Command - - Engineering - - Medical - - Science - - Security - - Service - - Supply - defaultChannel: Command + - type: ContainerFill + containers: + key_slots: + - EncryptionKeyCommand - type: Sprite sprite: Clothing/Ears/Headsets/command.rsi - type: Clothing @@ -58,15 +54,27 @@ - type: entity parent: ClothingHeadsetAlt - id: ClothingHeadsetAltMedical - name: medical over-ear headset + id: ClothingHeadsetAltEngineering + name: chief engineer's over-ear headset components: - - type: Headset - channels: - - Command - - Common - - Medical - defaultChannel: Medical + - type: ContainerFill + containers: + key_slots: + - EncryptionKeyCE + - type: Sprite + sprite: Clothing/Ears/Headsets/engineering.rsi + - type: Clothing + sprite: Clothing/Ears/Headsets/engineering.rsi + +- type: entity + parent: ClothingHeadsetAlt + id: ClothingHeadsetAltMedical + name: chief medical officer's over-ear headset + components: + - type: ContainerFill + containers: + key_slots: + - EncryptionKeyCMO - type: Sprite sprite: Clothing/Ears/Headsets/medical.rsi - type: Clothing @@ -75,77 +83,43 @@ - type: entity parent: ClothingHeadsetAlt id: ClothingHeadsetAltSecurity - name: security over-ear headset + name: head of security's over-ear headset components: - - type: Headset - channels: - - Command - - Common - - Security - defaultChannel: Security + - type: ContainerFill + containers: + key_slots: + - EncryptionKeyHOS - type: Sprite sprite: Clothing/Ears/Headsets/security.rsi - type: Clothing sprite: Clothing/Ears/Headsets/security.rsi -- type: entity - parent: ClothingHeadsetAlt - id: ClothingHeadsetAltEngineering - name: engineering over-ear headset - components: - - type: Headset - channels: - - Command - - Common - - Engineering - defaultChannel: Engineering - - type: Sprite - sprite: Clothing/Ears/Headsets/engineering.rsi - - type: Clothing - sprite: Clothing/Ears/Headsets/engineering.rsi - - type: entity parent: ClothingHeadsetAlt id: ClothingHeadsetAltScience - name: science over-ear headset + name: research director's over-ear headset components: - - type: Headset - channels: - - Command - - Common - - Science - defaultChannel: Science + - type: ContainerFill + containers: + key_slots: + - EncryptionKeyRD - type: Sprite sprite: Clothing/Ears/Headsets/science.rsi - type: Clothing sprite: Clothing/Ears/Headsets/science.rsi -- type: entity - parent: ClothingHeadsetAlt - id: ClothingHeadsetAltCargo - name: cargo over-ear headset - components: - - type: Headset - channels: - - Command - - Common - - Supply - defaultChannel: Supply - - type: Sprite - sprite: Clothing/Ears/Headsets/cargo.rsi - - type: Clothing - sprite: Clothing/Ears/Headsets/cargo.rsi - - type: entity parent: ClothingHeadsetAlt id: ClothingHeadsetAltSyndicate - name: syndicate over-ear headset - description: An updated, modular syndicate intercom that fits over the head and takes encryption keys. Protects ears from flashbangs. + name: blood-red over-ear headset + description: An updated, modular syndicate intercom that fits over the head and takes encryption keys (there are 4 slots for them). components: - type: Headset - channels: - - Syndicate - defaultChannel: Syndicate + keySlots: 4 + - type: ContainerFill + containers: + key_slots: + - EncryptionKeySyndie - type: Sprite sprite: Clothing/Ears/Headsets/syndicate.rsi - type: Clothing diff --git a/Resources/Prototypes/Entities/Objects/Devices/encryption_keys.yml b/Resources/Prototypes/Entities/Objects/Devices/encryption_keys.yml new file mode 100644 index 0000000000..e2aa9833f1 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Devices/encryption_keys.yml @@ -0,0 +1,287 @@ +- type: entity + abstract: true + parent: BaseItem + id: EncryptionKey + name: encryption key + description: A small cypher chip for headsets. + components: + - type: EncryptionKey + - type: Item + sprite: Objects/Devices/encryption_keys.rsi + - type: Sprite + sprite: Objects/Devices/encryption_keys.rsi + state: cypherkey + netsync: false + +- type: entity + parent: EncryptionKey + id: EncryptionKeyCommon + name: passenger encryption key + description: An encryption key used by anyone. + components: + - type: EncryptionKey + channels: + - Common + defaultChannel: Common + - type: Sprite + sprite: Objects/Devices/encryption_keys.rsi + state: cypherkey + +- type: entity + parent: EncryptionKey + id: EncryptionKeyCargo + name: cargo encryption key + description: An encryption key used by supply employees. + components: + - type: EncryptionKey + channels: + - Common + - Supply + defaultChannel: Supply + - type: Sprite + sprite: Objects/Devices/encryption_keys.rsi + state: cargo_cypherkey + +- type: entity + parent: EncryptionKey + id: EncryptionKeyQM + name: quartermaster's encryption key + description: An encryption key used by the boss of cargo. + components: + - type: EncryptionKey + channels: + - Common + - Command + - Supply + defaultChannel: Supply + - type: Sprite + sprite: Objects/Devices/encryption_keys.rsi + state: qm_cypherkey + +- type: entity + parent: EncryptionKey + id: EncryptionKeyCentCom + name: central command encryption key + description: An encryption key used by captain's bosses. + components: + - type: EncryptionKey + channels: + - Common + - Command + - CentCom + - Engineering + - Medical + - Science + - Security + - Service + - Supply + defaultChannel: CentCom + - type: Sprite + sprite: Objects/Devices/encryption_keys.rsi + state: bin_cypherkey + +- type: entity + parent: EncryptionKey + id: EncryptionKeyCommand + name: command encryption key + description: An encryption key used by crew's bosses. + components: + - type: EncryptionKey + channels: + - Common + - Command + - Engineering + - Medical + - Science + - Security + - Service + - Supply + defaultChannel: Command + - type: Sprite + sprite: Objects/Devices/encryption_keys.rsi + state: com_cypherkey + +- type: entity + parent: EncryptionKey + id: EncryptionKeyEngineering + name: engineering encryption key + description: An encryption key used by the engineers. + components: + - type: EncryptionKey + channels: + - Common + - Engineering + defaultChannel: Engineering + - type: Sprite + sprite: Objects/Devices/encryption_keys.rsi + state: eng_cypherkey + +- type: entity + parent: EncryptionKey + id: EncryptionKeyCE + name: chief engineer's encryption key + description: An encryption key used by the boss of the real men. + components: + - type: EncryptionKey + channels: + - Common + - Command + - Engineering + defaultChannel: Engineering + - type: Sprite + sprite: Objects/Devices/encryption_keys.rsi + state: ce_cypherkey + +- type: entity + parent: EncryptionKey + id: EncryptionKeyMedical + name: medical encryption key + description: An encryption key used by those who save lives. + components: + - type: EncryptionKey + channels: + - Common + - Medical + defaultChannel: Medical + - type: Sprite + sprite: Objects/Devices/encryption_keys.rsi + state: med_cypherkey + +- type: entity + parent: EncryptionKey + id: EncryptionKeyCMO + name: chief medical officer encryption key + description: An encryption key used by the head of the medical department. + components: + - type: EncryptionKey + channels: + - Common + - Command + - Medical + defaultChannel: Medical + - type: Sprite + sprite: Objects/Devices/encryption_keys.rsi + state: cmo_cypherkey + +- type: entity + parent: EncryptionKey + id: EncryptionKeyMedicalScience + name: med-sci encryption key + description: An encryption key used by someone who hasn't decided which side to take. + components: + - type: EncryptionKey + channels: + - Common + - Medical + - Science + defaultChannel: Science + - type: Sprite + sprite: Objects/Devices/encryption_keys.rsi + state: medsci_cypherkey + +- type: entity + parent: EncryptionKey + id: EncryptionKeyScience + name: science encryption key + description: An encryption key used by scientists. Maybe it is plasmaproof? + components: + - type: EncryptionKey + channels: + - Common + - Science + defaultChannel: Science + - type: Sprite + sprite: Objects/Devices/encryption_keys.rsi + state: sci_cypherkey + +- type: entity + parent: EncryptionKey + id: EncryptionKeyRobo + name: robotech encryption key + description: An encryption key used by robototech engineers. Maybe it has a LAH-6000 on it? + components: + - type: EncryptionKey + channels: + - Common + - Science + defaultChannel: Science + - type: Sprite + sprite: Objects/Devices/encryption_keys.rsi + state: rob_cypherkey + +- type: entity + parent: EncryptionKey + id: EncryptionKeyRD + name: research director's encryption key + description: An encryption key used by the head of the science department. Looks like it's been chewed on. + components: + - type: EncryptionKey + channels: + - Common + - Command + - Science + defaultChannel: Science + - type: Sprite + sprite: Objects/Devices/encryption_keys.rsi + state: rd_cypherkey + +- type: entity + parent: EncryptionKey + id: EncryptionKeySecurity + name: security encryption key + description: An encryption key used by security. + components: + - type: EncryptionKey + channels: + - Common + - Security + defaultChannel: Security + - type: Sprite + sprite: Objects/Devices/encryption_keys.rsi + state: sec_cypherkey + +- type: entity + parent: EncryptionKey + id: EncryptionKeyHOS + name: head of security encryption key + description: An encryption key used by the boss of security. + components: + - type: EncryptionKey + channels: + - Common + - Command + - Security + defaultChannel: Security + - type: Sprite + sprite: Objects/Devices/encryption_keys.rsi + state: hos_cypherkey + +- type: entity + parent: EncryptionKey + id: EncryptionKeyService + name: service encryption key + description: An encryption key used by the service staff, tasked with keeping the station full, happy and clean. + components: + - type: EncryptionKey + channels: + - Common + - Service + defaultChannel: Service + - type: Sprite + sprite: Objects/Devices/encryption_keys.rsi + state: srv_cypherkey + +- type: entity + parent: EncryptionKey + id: EncryptionKeySyndie + name: blood-red encryption key + description: An encryption key used by... wait... Who is owner of this chip? + components: + - type: EncryptionKey + channels: + - Common + - Syndicate + defaultChannel: Syndicate + - type: Sprite + sprite: Objects/Devices/encryption_keys.rsi + state: syn_cypherkey diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/bin_cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/bin_cypherkey.png new file mode 100644 index 0000000000..3b8647c610 Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/bin_cypherkey.png differ diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/cap_cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/cap_cypherkey.png new file mode 100644 index 0000000000..830d7b2bb5 Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/cap_cypherkey.png differ diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/cargo_cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/cargo_cypherkey.png new file mode 100644 index 0000000000..9e4f74a0ec Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/cargo_cypherkey.png differ diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/ce_cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/ce_cypherkey.png new file mode 100644 index 0000000000..da72b41527 Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/ce_cypherkey.png differ diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/cmo_cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/cmo_cypherkey.png new file mode 100644 index 0000000000..6ff0d4563f Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/cmo_cypherkey.png differ diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/com_cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/com_cypherkey.png new file mode 100644 index 0000000000..32d6779174 Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/com_cypherkey.png differ diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/cypherkey.png new file mode 100644 index 0000000000..093a913b3d Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/cypherkey.png differ diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/eng_cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/eng_cypherkey.png new file mode 100644 index 0000000000..580f7776eb Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/eng_cypherkey.png differ diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/hop_cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/hop_cypherkey.png new file mode 100644 index 0000000000..ee5b4ef5e8 Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/hop_cypherkey.png differ diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/hos_cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/hos_cypherkey.png new file mode 100644 index 0000000000..f7b96b0f47 Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/hos_cypherkey.png differ diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/med_cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/med_cypherkey.png new file mode 100644 index 0000000000..8ccf581185 Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/med_cypherkey.png differ diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/medsci_cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/medsci_cypherkey.png new file mode 100644 index 0000000000..3efc63976a Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/medsci_cypherkey.png differ diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/meta.json b/Resources/Textures/Objects/Devices/encryption_keys.rsi/meta.json new file mode 100644 index 0000000000..04c8803e66 --- /dev/null +++ b/Resources/Textures/Objects/Devices/encryption_keys.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from infinity baystation 12, https://github.com/infinitystation/Baystation12/blob/073f678cdce92edb8fcd55f9ffc9f0523bf31506/icons/obj/radio.dmi", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + {"name": "cypherkey"}, + {"name": "bin_cypherkey"}, + {"name": "cap_cypherkey"}, + {"name": "cargo_cypherkey"}, + {"name": "ce_cypherkey"}, + {"name": "cmo_cypherkey"}, + {"name": "com_cypherkey"}, + {"name": "eng_cypherkey"}, + {"name": "hop_cypherkey"}, + {"name": "hos_cypherkey"}, + {"name": "medsci_cypherkey"}, + {"name": "med_cypherkey"}, + {"name": "mine_cypherkey"}, + {"name": "nt_cypherkey"}, + {"name": "qm_cypherkey"}, + {"name": "rd_cypherkey"}, + {"name": "rob_cypherkey"}, + {"name": "sci_cypherkey"}, + {"name": "sec_cypherkey"}, + {"name": "srv_cypherkey"}, + {"name": "syn_cypherkey"} + ] +} diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/mine_cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/mine_cypherkey.png new file mode 100644 index 0000000000..4705ce55e6 Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/mine_cypherkey.png differ diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/nt_cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/nt_cypherkey.png new file mode 100644 index 0000000000..a29ae041ae Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/nt_cypherkey.png differ diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/qm_cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/qm_cypherkey.png new file mode 100644 index 0000000000..24d667b545 Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/qm_cypherkey.png differ diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/rd_cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/rd_cypherkey.png new file mode 100644 index 0000000000..17e96526fe Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/rd_cypherkey.png differ diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/rob_cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/rob_cypherkey.png new file mode 100644 index 0000000000..d4a818480e Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/rob_cypherkey.png differ diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/sci_cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/sci_cypherkey.png new file mode 100644 index 0000000000..b5b79f7fcf Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/sci_cypherkey.png differ diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/sec_cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/sec_cypherkey.png new file mode 100644 index 0000000000..860127b346 Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/sec_cypherkey.png differ diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/srv_cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/srv_cypherkey.png new file mode 100644 index 0000000000..bafc6c04e3 Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/srv_cypherkey.png differ diff --git a/Resources/Textures/Objects/Devices/encryption_keys.rsi/syn_cypherkey.png b/Resources/Textures/Objects/Devices/encryption_keys.rsi/syn_cypherkey.png new file mode 100644 index 0000000000..f02db61884 Binary files /dev/null and b/Resources/Textures/Objects/Devices/encryption_keys.rsi/syn_cypherkey.png differ