diff --git a/Content.Client/Entry/IgnoredComponents.cs b/Content.Client/Entry/IgnoredComponents.cs index 860dcc3d8e..6694b7c108 100644 --- a/Content.Client/Entry/IgnoredComponents.cs +++ b/Content.Client/Entry/IgnoredComponents.cs @@ -57,6 +57,7 @@ namespace Content.Client.Entry "CablePlacer", "Drink", "Food", + "DeployableBarrier", "MagicMirror", "FloorTile", "ShuttleController", diff --git a/Content.Client/Security/DeployableBarrierVisualizer.cs b/Content.Client/Security/DeployableBarrierVisualizer.cs new file mode 100644 index 0000000000..4551440725 --- /dev/null +++ b/Content.Client/Security/DeployableBarrierVisualizer.cs @@ -0,0 +1,39 @@ +using Content.Shared.Security; +using JetBrains.Annotations; +using Robust.Client.GameObjects; + +namespace Content.Client.Security +{ + [UsedImplicitly] + public class DeployableBarrierVisualizer : AppearanceVisualizer + { + public override void OnChangeData(AppearanceComponent component) + { + base.OnChangeData(component); + + if (!component.Owner.TryGetComponent(out SpriteComponent? sprite)) + return; + + if (!component.TryGetData(DeployableBarrierVisuals.State, out DeployableBarrierState state)) + return; + + switch (state) + { + case DeployableBarrierState.Idle: + sprite.LayerSetState(0, "idle"); + ToggleLight(component, false); + break; + case DeployableBarrierState.Deployed: + sprite.LayerSetState(0, "deployed"); + ToggleLight(component, true); + break; + } + } + + private void ToggleLight(AppearanceComponent component, bool enabled) + { + if (component.Owner.TryGetComponent(out PointLightComponent? light)) + light.Enabled = enabled; + } + } +} diff --git a/Content.Server/Lock/LockComponent.cs b/Content.Server/Lock/LockComponent.cs index 8d1d94c7e0..3e9a26716b 100644 --- a/Content.Server/Lock/LockComponent.cs +++ b/Content.Server/Lock/LockComponent.cs @@ -20,6 +20,7 @@ namespace Content.Server.Storage.Components public override string Name => "Lock"; [ViewVariables(VVAccess.ReadWrite)] [DataField("locked")] public bool Locked { get; set; } = true; + [ViewVariables(VVAccess.ReadWrite)] [DataField("lockOnClick")] public bool LockOnClick { get; set; } = false; [ViewVariables(VVAccess.ReadWrite)] [DataField("unlockingSound")] public SoundSpecifier UnlockSound { get; set; } = new SoundPathSpecifier("/Audio/Machines/door_lock_off.ogg"); [ViewVariables(VVAccess.ReadWrite)] [DataField("lockingSound")] public SoundSpecifier LockSound { get; set; } = new SoundPathSpecifier("/Audio/Machines/door_lock_off.ogg"); diff --git a/Content.Server/Lock/LockSystem.cs b/Content.Server/Lock/LockSystem.cs index 063ac1656a..d8b6c65190 100644 --- a/Content.Server/Lock/LockSystem.cs +++ b/Content.Server/Lock/LockSystem.cs @@ -43,6 +43,11 @@ namespace Content.Server.Lock { DoUnlock(lockComp, args); } + else + { + if (lockComp.LockOnClick) + DoLock(lockComp, args); + } } private void OnExamined(EntityUid eUI, LockComponent lockComp, ExaminedEvent args) @@ -73,6 +78,8 @@ namespace Content.Server.Lock appearanceComp.SetData(StorageVisuals.Locked, true); } + RaiseLocalEvent(lockComp.Owner.Uid, new LockToggledEvent(true)); + args.Handled = true; } @@ -95,6 +102,8 @@ namespace Content.Server.Lock appearanceComp.SetData(StorageVisuals.Locked, false); } + RaiseLocalEvent(lockComp.Owner.Uid, new LockToggledEvent(false)); + // To stop EntityStorageComponent from opening right after the container gets unlocked args.Handled = true; } diff --git a/Content.Server/Lock/LockToggledEvent.cs b/Content.Server/Lock/LockToggledEvent.cs new file mode 100644 index 0000000000..04ae77010b --- /dev/null +++ b/Content.Server/Lock/LockToggledEvent.cs @@ -0,0 +1,14 @@ +using Robust.Shared.GameObjects; + +namespace Content.Server.Lock +{ + public class LockToggledEvent : EntityEventArgs + { + public readonly bool Locked; + + public LockToggledEvent(bool locked) + { + Locked = locked; + } + } +} diff --git a/Content.Server/Security/Components/DeployableBarrierComponent.cs b/Content.Server/Security/Components/DeployableBarrierComponent.cs new file mode 100644 index 0000000000..f71d51a093 --- /dev/null +++ b/Content.Server/Security/Components/DeployableBarrierComponent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.GameObjects; + +namespace Content.Server.Security +{ + [RegisterComponent] + public class DeployableBarrierComponent : Component + { + public override string Name => "DeployableBarrier"; + } +} diff --git a/Content.Server/Security/Systems/DeployableBarrierSystem.cs b/Content.Server/Security/Systems/DeployableBarrierSystem.cs new file mode 100644 index 0000000000..d819fcb651 --- /dev/null +++ b/Content.Server/Security/Systems/DeployableBarrierSystem.cs @@ -0,0 +1,43 @@ +using Content.Server.Lock; +using Content.Server.Storage.Components; +using Content.Shared.Security; +using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; +using System; + +namespace Content.Server.Security.Systems +{ + public class DeployableBarrierSystem : EntitySystem + { + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent(OnLockToggled); + } + + private void OnStartup(EntityUid uid, DeployableBarrierComponent component, ComponentStartup args) + { + if (!component.Owner.TryGetComponent(out LockComponent? lockComponent)) + return; + + ToggleBarrierDeploy(component, lockComponent.Locked); + } + + private void OnLockToggled(EntityUid uid, DeployableBarrierComponent component, LockToggledEvent args) + { + ToggleBarrierDeploy(component, args.Locked); + } + + private void ToggleBarrierDeploy(DeployableBarrierComponent component, bool isDeployed) + { + component.Owner.Transform.Anchored = isDeployed; + + if (!component.Owner.TryGetComponent(out AppearanceComponent? appearanceComponent)) + return; + + var state = isDeployed ? DeployableBarrierState.Deployed : DeployableBarrierState.Idle; + appearanceComponent.SetData(DeployableBarrierVisuals.State, state); + } + } +} diff --git a/Content.Shared/Security/DeployableBarrierVisuals.cs b/Content.Shared/Security/DeployableBarrierVisuals.cs new file mode 100644 index 0000000000..a25a925d35 --- /dev/null +++ b/Content.Shared/Security/DeployableBarrierVisuals.cs @@ -0,0 +1,23 @@ +using Robust.Shared.Serialization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Content.Shared.Security +{ + [Serializable, NetSerializable] + public enum DeployableBarrierVisuals : byte + { + State + } + + + [Serializable, NetSerializable] + public enum DeployableBarrierState : byte + { + Idle, + Deployed + } +} diff --git a/Resources/Prototypes/Entities/Objects/Specific/Security/barrier.yml b/Resources/Prototypes/Entities/Objects/Specific/Security/barrier.yml new file mode 100644 index 0000000000..6447a30d2f --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Specific/Security/barrier.yml @@ -0,0 +1,55 @@ +- type: entity + name: deployable barrier + id: DeployableBarrier + description: A deployable barrier. Swipe your ID card to lock/unlock it. + parent: BaseStructure + components: + - type: Sprite + sprite: Objects/Specific/Security/barrier.rsi + netsync: false + state: idle + - type: InteractionOutline + - type: Physics + fixtures: + - shape: + !type:PhysShapeCircle + radius: 0.45 + layer: + - Opaque + - Impassable + - VaultImpassable + - SmallImpassable + mask: + - Impassable + mass: 150 + - type: AccessReader + access: [["Security"]] + - type: Lock + locked: false + lockOnClick: true # toggle lock just by clicking on barrier + - type: DeployableBarrier + - type: Damageable + resistances: metallicResistances + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 300 + behaviors: + - !type:SpawnEntitiesBehavior + spawn: + SheetSteel: + min: 5 + max: 5 + - !type:PlaySoundBehavior + sound: + path: /Audio/Effects/metalbreak.ogg + - !type:DoActsBehavior + acts: [ "Destruction" ] + - type: PointLight + enabled: false + radius: 3 + color: red + - type: Appearance + visuals: + - type: DeployableBarrierVisualizer diff --git a/Resources/Textures/Objects/Specific/Security/barrier.rsi/deployed.png b/Resources/Textures/Objects/Specific/Security/barrier.rsi/deployed.png new file mode 100644 index 0000000000..a3c0f1f3af Binary files /dev/null and b/Resources/Textures/Objects/Specific/Security/barrier.rsi/deployed.png differ diff --git a/Resources/Textures/Objects/Specific/Security/barrier.rsi/idle.png b/Resources/Textures/Objects/Specific/Security/barrier.rsi/idle.png new file mode 100644 index 0000000000..e4853d5dc7 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Security/barrier.rsi/idle.png differ diff --git a/Resources/Textures/Objects/Specific/Security/barrier.rsi/meta.json b/Resources/Textures/Objects/Specific/Security/barrier.rsi/meta.json new file mode 100644 index 0000000000..8142924b68 --- /dev/null +++ b/Resources/Textures/Objects/Specific/Security/barrier.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from cev-eris at https://github.com/discordia-space/CEV-Eris/commit/476e374cea95ff5e8b1603c48342bf700e2cd7af", + "states": [ + { + "name": "idle" + }, + { + "name": "deployed", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.5 + ] + ] + } + ] +} \ No newline at end of file