diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs index 9a1bf537f5..4da6cb6b7d 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs @@ -14,317 +14,337 @@ using Content.Shared.Database; using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; using Content.Shared.Lock; -using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Shared.Containers; -namespace Content.Server.Atmos.Piping.Unary.EntitySystems +namespace Content.Server.Atmos.Piping.Unary.EntitySystems; + +public sealed class GasCanisterSystem : EntitySystem { - [UsedImplicitly] - public sealed class GasCanisterSystem : EntitySystem + [Dependency] private readonly AtmosphereSystem _atmos = default!; + [Dependency] private readonly IAdminLogManager _adminLogger = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; + [Dependency] private readonly PopupSystem _popup = default!; + [Dependency] private readonly UserInterfaceSystem _ui = default!; + + public override void Initialize() { - [Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!; - [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; - [Dependency] private readonly IAdminLogManager _adminLogger = default!; - [Dependency] private readonly SharedContainerSystem _containerSystem = default!; - [Dependency] private readonly SharedHandsSystem _handsSystem = default!; - [Dependency] private readonly PopupSystem _popupSystem = default!; - [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!; - [Dependency] private readonly SharedAudioSystem _audioSys = default!; + base.Initialize(); - public override void Initialize() + SubscribeLocalEvent(OnCanisterStartup); + SubscribeLocalEvent(OnCanisterUpdated); + SubscribeLocalEvent(OnCanisterActivate); + SubscribeLocalEvent(OnCanisterInteractHand); + SubscribeLocalEvent(OnCanisterInteractUsing); + SubscribeLocalEvent(OnCanisterContainerInserted); + SubscribeLocalEvent(OnCanisterContainerRemoved); + SubscribeLocalEvent(CalculateCanisterPrice); + SubscribeLocalEvent(OnAnalyzed); + // Bound UI subscriptions + SubscribeLocalEvent(OnHoldingTankEjectMessage); + SubscribeLocalEvent(OnCanisterChangeReleasePressure); + SubscribeLocalEvent(OnCanisterChangeReleaseValve); + SubscribeLocalEvent(OnLockToggled); + } + + /// + /// Completely dumps the content of the canister into the world. + /// + public void PurgeContents(EntityUid uid, GasCanisterComponent? canister = null, TransformComponent? transform = null) + { + if (!Resolve(uid, ref canister, ref transform)) + return; + + var environment = _atmos.GetContainingMixture(uid, false, true); + + if (environment is not null) + _atmos.Merge(environment, canister.Air); + + _adminLogger.Add(LogType.CanisterPurged, LogImpact.Medium, $"Canister {ToPrettyString(uid):canister} purged its contents of {canister.Air:gas} into the environment."); + canister.Air.Clear(); + } + + private void OnCanisterStartup(EntityUid uid, GasCanisterComponent comp, ComponentStartup args) + { + // Ensure container manager. + var containerManager = EnsureComp(uid); + + // Ensure container. + _container.EnsureContainer(uid, comp.ContainerName, containerManager); + + if (TryComp(uid, out var lockComp)) { - base.Initialize(); + _appearance.SetData(uid, GasCanisterVisuals.Locked, lockComp.Locked); + } + } - SubscribeLocalEvent(OnCanisterStartup); - SubscribeLocalEvent(OnCanisterUpdated); - SubscribeLocalEvent(OnCanisterActivate); - SubscribeLocalEvent(OnCanisterInteractHand); - SubscribeLocalEvent(OnCanisterInteractUsing); - SubscribeLocalEvent(OnCanisterContainerInserted); - SubscribeLocalEvent(OnCanisterContainerRemoved); - SubscribeLocalEvent(CalculateCanisterPrice); - SubscribeLocalEvent(OnAnalyzed); - // Bound UI subscriptions - SubscribeLocalEvent(OnHoldingTankEjectMessage); - SubscribeLocalEvent(OnCanisterChangeReleasePressure); - SubscribeLocalEvent(OnCanisterChangeReleaseValve); - SubscribeLocalEvent(OnLockToggled); + private void DirtyUI(EntityUid uid, + GasCanisterComponent? canister = null, NodeContainerComponent? nodeContainer = null, + ContainerManagerComponent? containerManager = null) + { + if (!Resolve(uid, ref canister, ref nodeContainer, ref containerManager)) + return; + var portStatus = false; + string? tankLabel = null; + var tankPressure = 0f; + + if (nodeContainer.TryGetNode(canister.PortName, out PipeNode? portNode) && portNode.NodeGroup?.Nodes.Count > 1) + portStatus = true; + + if (containerManager.TryGetContainer(canister.ContainerName, out var tankContainer) + && tankContainer.ContainedEntities.Count > 0) + { + var tank = tankContainer.ContainedEntities[0]; + var tankComponent = Comp(tank); + tankLabel = Name(tank); + tankPressure = tankComponent.Air.Pressure; } - /// - /// Completely dumps the content of the canister into the world. - /// - public void PurgeContents(EntityUid uid, GasCanisterComponent? canister = null, TransformComponent? transform = null) + _ui.TrySetUiState(uid, GasCanisterUiKey.Key, + new GasCanisterBoundUserInterfaceState(Name(uid), + canister.Air.Pressure, portStatus, tankLabel, tankPressure, canister.ReleasePressure, + canister.ReleaseValve, canister.MinReleasePressure, canister.MaxReleasePressure)); + } + + private void OnHoldingTankEjectMessage(EntityUid uid, GasCanisterComponent canister, GasCanisterHoldingTankEjectMessage args) + { + if (!TryComp(uid, out var containerManager) + || !containerManager.TryGetContainer(canister.ContainerName, out var container)) + return; + + if (container.ContainedEntities.Count == 0) + return; + + _adminLogger.Add(LogType.CanisterTankEjected, LogImpact.Medium, $"Player {ToPrettyString(args.Session.AttachedEntity.GetValueOrDefault()):player} ejected tank {ToPrettyString(container.ContainedEntities[0]):tank} from {ToPrettyString(uid):canister}"); + container.Remove(container.ContainedEntities[0]); + } + + private void OnCanisterChangeReleasePressure(EntityUid uid, GasCanisterComponent canister, GasCanisterChangeReleasePressureMessage args) + { + var pressure = Math.Clamp(args.Pressure, canister.MinReleasePressure, canister.MaxReleasePressure); + + _adminLogger.Add(LogType.CanisterPressure, LogImpact.Medium, $"{ToPrettyString(args.Session.AttachedEntity.GetValueOrDefault()):player} set the release pressure on {ToPrettyString(uid):canister} to {args.Pressure}"); + + canister.ReleasePressure = pressure; + DirtyUI(uid, canister); + } + + private void OnCanisterChangeReleaseValve(EntityUid uid, GasCanisterComponent canister, GasCanisterChangeReleaseValveMessage args) + { + var impact = LogImpact.High; + if (TryComp(uid, out var containerManager) + && containerManager.TryGetContainer(canister.ContainerName, out var container)) { - if (!Resolve(uid, ref canister, ref transform)) - return; - - var environment = _atmosphereSystem.GetContainingMixture(uid, false, true); - - if (environment is not null) - _atmosphereSystem.Merge(environment, canister.Air); - - _adminLogger.Add(LogType.CanisterPurged, LogImpact.Medium, $"Canister {ToPrettyString(uid):canister} purged its contents of {canister.Air:gas} into the environment."); - canister.Air.Clear(); + // filling a jetpack with plasma is less important than filling a room with it + impact = container.ContainedEntities.Count != 0 ? LogImpact.Medium : LogImpact.High; } - private void OnCanisterStartup(EntityUid uid, GasCanisterComponent canister, ComponentStartup args) + var containedGasDict = new Dictionary(); + var containedGasArray = Gas.GetValues(typeof(Gas)); + + for (int i = 0; i < containedGasArray.Length; i++) { - // Ensure container manager. - var containerManager = EntityManager.EnsureComponent(uid); - - // Ensure container. - if (!containerManager.TryGetContainer(canister.ContainerName, out _)) - { - containerManager.MakeContainer(canister.ContainerName); - } - - if (TryComp(uid, out var lockComponent)) - _appearanceSystem.SetData(uid, GasCanisterVisuals.Locked, lockComponent.Locked); + containedGasDict.Add((Gas)i, canister.Air.Moles[i]); } - private void DirtyUI(EntityUid uid, - GasCanisterComponent? canister = null, NodeContainerComponent? nodeContainer = null, - ContainerManagerComponent? containerManager = null) + _adminLogger.Add(LogType.CanisterValve, impact, $"{ToPrettyString(args.Session.AttachedEntity.GetValueOrDefault()):player} set the valve on {ToPrettyString(uid):canister} to {args.Valve:valveState} while it contained [{string.Join(", ", containedGasDict)}]"); + + canister.ReleaseValve = args.Valve; + DirtyUI(uid, canister); + } + + private void OnCanisterUpdated(EntityUid uid, GasCanisterComponent canister, AtmosDeviceUpdateEvent args) + { + _atmos.React(canister.Air, canister); + + if (!TryComp(uid, out var nodeContainer) + || !TryComp(uid, out var appearance)) + return; + + if (!nodeContainer.TryGetNode(canister.PortName, out PortablePipeNode? portNode)) + return; + + if (portNode.NodeGroup is PipeNet {NodeCount: > 1} net) { - if (!Resolve(uid, ref canister, ref nodeContainer, ref containerManager)) - return; - - var portStatus = false; - string? tankLabel = null; - var tankPressure = 0f; - - if (nodeContainer.TryGetNode(canister.PortName, out PipeNode? portNode) && portNode.NodeGroup?.Nodes.Count > 1) - portStatus = true; - - if (containerManager.TryGetContainer(canister.ContainerName, out var tankContainer) - && tankContainer.ContainedEntities.Count > 0) - { - var tank = tankContainer.ContainedEntities[0]; - var tankComponent = EntityManager.GetComponent(tank); - tankLabel = EntityManager.GetComponent(tank).EntityName; - tankPressure = tankComponent.Air.Pressure; - } - - _userInterfaceSystem.TrySetUiState(uid, GasCanisterUiKey.Key, - new GasCanisterBoundUserInterfaceState(EntityManager.GetComponent(canister.Owner).EntityName, - canister.Air.Pressure, portStatus, tankLabel, tankPressure, canister.ReleasePressure, - canister.ReleaseValve, canister.MinReleasePressure, canister.MaxReleasePressure)); + MixContainerWithPipeNet(canister.Air, net.Air); } - private void OnHoldingTankEjectMessage(EntityUid uid, GasCanisterComponent canister, GasCanisterHoldingTankEjectMessage args) + ContainerManagerComponent? containerManager = null; + + // Release valve is open, release gas. + if (canister.ReleaseValve) { - if (!EntityManager.TryGetComponent(uid, out ContainerManagerComponent? containerManager) + if (!TryComp(uid, out containerManager) || !containerManager.TryGetContainer(canister.ContainerName, out var container)) return; - if (container.ContainedEntities.Count == 0) - return; - - _adminLogger.Add(LogType.CanisterTankEjected, LogImpact.Medium, $"Player {ToPrettyString(args.Session.AttachedEntity.GetValueOrDefault()):player} ejected tank {ToPrettyString(container.ContainedEntities[0]):tank} from {ToPrettyString(uid):canister}"); - container.Remove(container.ContainedEntities[0]); - } - - private void OnCanisterChangeReleasePressure(EntityUid uid, GasCanisterComponent canister, GasCanisterChangeReleasePressureMessage args) - { - var pressure = Math.Clamp(args.Pressure, canister.MinReleasePressure, canister.MaxReleasePressure); - - _adminLogger.Add(LogType.CanisterPressure, LogImpact.Medium, $"{ToPrettyString(args.Session.AttachedEntity.GetValueOrDefault()):player} set the release pressure on {ToPrettyString(uid):canister} to {args.Pressure}"); - - canister.ReleasePressure = pressure; - DirtyUI(uid, canister); - } - - private void OnCanisterChangeReleaseValve(EntityUid uid, GasCanisterComponent canister, GasCanisterChangeReleaseValveMessage args) - { - var impact = LogImpact.High; - if (EntityManager.TryGetComponent(uid, out ContainerManagerComponent? containerManager) - && containerManager.TryGetContainer(canister.ContainerName, out var container)) - impact = container.ContainedEntities.Count != 0 ? LogImpact.Medium : LogImpact.High; - - var containedGasDict = new Dictionary(); - var containedGasArray = Gas.GetValues(typeof(Gas)); - - for (int i = 0; i < containedGasArray.Length; i++) + if (container.ContainedEntities.Count > 0) { - containedGasDict.Add((Gas)i, canister.Air.Moles[i]); - } - - _adminLogger.Add(LogType.CanisterValve, impact, $"{ToPrettyString(args.Session.AttachedEntity.GetValueOrDefault()):player} set the valve on {ToPrettyString(uid):canister} to {args.Valve:valveState} while it contained [{string.Join(", ", containedGasDict)}]"); - - canister.ReleaseValve = args.Valve; - DirtyUI(uid, canister); - } - - private void OnCanisterUpdated(EntityUid uid, GasCanisterComponent canister, AtmosDeviceUpdateEvent args) - { - _atmosphereSystem.React(canister.Air, canister); - - if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) - || !EntityManager.TryGetComponent(uid, out AppearanceComponent? appearance)) - return; - - if (!nodeContainer.TryGetNode(canister.PortName, out PortablePipeNode? portNode)) - return; - - if (portNode.NodeGroup is PipeNet {NodeCount: > 1} net) - { - MixContainerWithPipeNet(canister.Air, net.Air); - } - - ContainerManagerComponent? containerManager = null; - - // Release valve is open, release gas. - if (canister.ReleaseValve) - { - if (!EntityManager.TryGetComponent(uid, out containerManager) - || !containerManager.TryGetContainer(canister.ContainerName, out var container)) - return; - - if (container.ContainedEntities.Count > 0) - { - var gasTank = EntityManager.GetComponent(container.ContainedEntities[0]); - _atmosphereSystem.ReleaseGasTo(canister.Air, gasTank.Air, canister.ReleasePressure); - } - else - { - var environment = _atmosphereSystem.GetContainingMixture(uid, false, true); - _atmosphereSystem.ReleaseGasTo(canister.Air, environment, canister.ReleasePressure); - } - } - - // If last pressure is very close to the current pressure, do nothing. - if (MathHelper.CloseToPercent(canister.Air.Pressure, canister.LastPressure)) - return; - - DirtyUI(uid, canister, nodeContainer, containerManager); - - canister.LastPressure = canister.Air.Pressure; - - if (canister.Air.Pressure < 10) - { - _appearanceSystem.SetData(uid, GasCanisterVisuals.PressureState, 0, appearance); - } - else if (canister.Air.Pressure < Atmospherics.OneAtmosphere) - { - _appearanceSystem.SetData(uid, GasCanisterVisuals.PressureState, 1, appearance); - } - else if (canister.Air.Pressure < (15 * Atmospherics.OneAtmosphere)) - { - _appearanceSystem.SetData(uid, GasCanisterVisuals.PressureState, 2, appearance); + var gasTank = Comp(container.ContainedEntities[0]); + _atmos.ReleaseGasTo(canister.Air, gasTank.Air, canister.ReleasePressure); } else { - _appearanceSystem.SetData(uid, GasCanisterVisuals.PressureState, 3, appearance); + var environment = _atmos.GetContainingMixture(uid, false, true); + _atmos.ReleaseGasTo(canister.Air, environment, canister.ReleasePressure); } } - private void OnCanisterActivate(EntityUid uid, GasCanisterComponent component, ActivateInWorldEvent args) - { - if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor)) - return; - if (TryComp(uid, out var lockComponent) && lockComponent.Locked) - { - _popupSystem.PopupEntity(Loc.GetString("gas-canister-popup-denied"), uid, args.User); - if (component.AccessDeniedSound != null) - _audioSys.PlayPvs(component.AccessDeniedSound, uid); - return; - } + // If last pressure is very close to the current pressure, do nothing. + if (MathHelper.CloseToPercent(canister.Air.Pressure, canister.LastPressure)) + return; - _userInterfaceSystem.TryOpen(uid, GasCanisterUiKey.Key, actor.PlayerSession); - args.Handled = true; + DirtyUI(uid, canister, nodeContainer, containerManager); + + canister.LastPressure = canister.Air.Pressure; + + if (canister.Air.Pressure < 10) + { + _appearance.SetData(uid, GasCanisterVisuals.PressureState, 0, appearance); } - - - private void OnCanisterInteractHand(EntityUid uid, GasCanisterComponent component, InteractHandEvent args) + else if (canister.Air.Pressure < Atmospherics.OneAtmosphere) { - if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor)) - return; - if (TryComp(uid, out var lockComponent) && lockComponent.Locked) - return; - - _userInterfaceSystem.TryOpen(uid, GasCanisterUiKey.Key, actor.PlayerSession); - args.Handled = true; + _appearance.SetData(uid, GasCanisterVisuals.PressureState, 1, appearance); } - - private void OnCanisterInteractUsing(EntityUid canister, GasCanisterComponent component, InteractUsingEvent args) + else if (canister.Air.Pressure < (15 * Atmospherics.OneAtmosphere)) { - var container = _containerSystem.EnsureContainer(canister, component.ContainerName); - - // Container full. - if (container.ContainedEntity != null) - return; - - // Check the used item is valid... - if (!EntityManager.TryGetComponent(args.Used, out GasTankComponent? _)) - return; - - if (!_handsSystem.TryDropIntoContainer(args.User, args.Used, container)) - return; - - _adminLogger.Add(LogType.CanisterTankInserted, LogImpact.Medium, $"Player {ToPrettyString(args.User):player} inserted tank {ToPrettyString(container.ContainedEntities[0]):tank} into {ToPrettyString(canister):canister}"); - - args.Handled = true; + _appearance.SetData(uid, GasCanisterVisuals.PressureState, 2, appearance); } - - private void OnCanisterContainerInserted(EntityUid uid, GasCanisterComponent component, EntInsertedIntoContainerMessage args) + else { - if (args.Container.ID != component.ContainerName) - return; - - DirtyUI(uid, component); - - _appearanceSystem.SetData(uid, GasCanisterVisuals.TankInserted, true); - } - - private void OnCanisterContainerRemoved(EntityUid uid, GasCanisterComponent component, EntRemovedFromContainerMessage args) - { - if (args.Container.ID != component.ContainerName) - return; - - DirtyUI(uid, component); - - _appearanceSystem.SetData(uid, GasCanisterVisuals.TankInserted, false); - } - - /// - /// Mix air from a gas container into a pipe net. - /// Useful for anything that uses connector ports. - /// - public void MixContainerWithPipeNet(GasMixture containerAir, GasMixture pipeNetAir) - { - var buffer = new GasMixture(pipeNetAir.Volume + containerAir.Volume); - - _atmosphereSystem.Merge(buffer, pipeNetAir); - _atmosphereSystem.Merge(buffer, containerAir); - - pipeNetAir.Clear(); - _atmosphereSystem.Merge(pipeNetAir, buffer); - pipeNetAir.Multiply(pipeNetAir.Volume / buffer.Volume); - - containerAir.Clear(); - _atmosphereSystem.Merge(containerAir, buffer); - containerAir.Multiply(containerAir.Volume / buffer.Volume); - } - - private void CalculateCanisterPrice(EntityUid uid, GasCanisterComponent component, ref PriceCalculationEvent args) - { - args.Price += _atmosphereSystem.GetPrice(component.Air); - } - - /// - /// Returns the gas mixture for the gas analyzer - /// - private void OnAnalyzed(EntityUid uid, GasCanisterComponent component, GasAnalyzerScanEvent args) - { - args.GasMixtures = new Dictionary { {Name(uid), component.Air} }; - } - - private void OnLockToggled(EntityUid uid, GasCanisterComponent component, ref LockToggledEvent args) - { - _appearanceSystem.SetData(uid, GasCanisterVisuals.Locked, args.Locked); + _appearance.SetData(uid, GasCanisterVisuals.PressureState, 3, appearance); } } + + private void OnCanisterActivate(EntityUid uid, GasCanisterComponent component, ActivateInWorldEvent args) + { + if (!TryComp(args.User, out var actor)) + return; + + if (CheckLocked(uid, component, args.User)) + return; + + _ui.TryOpen(uid, GasCanisterUiKey.Key, actor.PlayerSession); + args.Handled = true; + } + + private void OnCanisterInteractHand(EntityUid uid, GasCanisterComponent component, InteractHandEvent args) + { + if (!TryComp(args.User, out var actor)) + return; + + if (CheckLocked(uid, component, args.User)) + return; + + _ui.TryOpen(uid, GasCanisterUiKey.Key, actor.PlayerSession); + args.Handled = true; + } + + private void OnCanisterInteractUsing(EntityUid uid, GasCanisterComponent component, InteractUsingEvent args) + { + var container = _container.EnsureContainer(uid, component.ContainerName); + + // Container full. + if (container.ContainedEntity != null) + return; + + // Check the used item is valid... + if (!HasComp(args.Used)) + return; + + // Preventing inserting a tank since if its locked you cant remove it. + if (CheckLocked(uid, component, args.User)) + return; + + if (!_hands.TryDropIntoContainer(args.User, args.Used, container)) + return; + + _adminLogger.Add(LogType.CanisterTankInserted, LogImpact.Medium, $"Player {ToPrettyString(args.User):player} inserted tank {ToPrettyString(container.ContainedEntities[0]):tank} into {ToPrettyString(uid):canister}"); + + args.Handled = true; + } + + private void OnCanisterContainerInserted(EntityUid uid, GasCanisterComponent component, EntInsertedIntoContainerMessage args) + { + if (args.Container.ID != component.ContainerName) + return; + + DirtyUI(uid, component); + + _appearance.SetData(uid, GasCanisterVisuals.TankInserted, true); + } + + private void OnCanisterContainerRemoved(EntityUid uid, GasCanisterComponent component, EntRemovedFromContainerMessage args) + { + if (args.Container.ID != component.ContainerName) + return; + + DirtyUI(uid, component); + + _appearance.SetData(uid, GasCanisterVisuals.TankInserted, false); + } + + /// + /// Mix air from a gas container into a pipe net. + /// Useful for anything that uses connector ports. + /// + public void MixContainerWithPipeNet(GasMixture containerAir, GasMixture pipeNetAir) + { + var buffer = new GasMixture(pipeNetAir.Volume + containerAir.Volume); + + _atmos.Merge(buffer, pipeNetAir); + _atmos.Merge(buffer, containerAir); + + pipeNetAir.Clear(); + _atmos.Merge(pipeNetAir, buffer); + pipeNetAir.Multiply(pipeNetAir.Volume / buffer.Volume); + + containerAir.Clear(); + _atmos.Merge(containerAir, buffer); + containerAir.Multiply(containerAir.Volume / buffer.Volume); + } + + private void CalculateCanisterPrice(EntityUid uid, GasCanisterComponent component, ref PriceCalculationEvent args) + { + args.Price += _atmos.GetPrice(component.Air); + } + + /// + /// Returns the gas mixture for the gas analyzer + /// + private void OnAnalyzed(EntityUid uid, GasCanisterComponent component, GasAnalyzerScanEvent args) + { + args.GasMixtures = new Dictionary { {Name(uid), component.Air} }; + } + + private void OnLockToggled(EntityUid uid, GasCanisterComponent component, ref LockToggledEvent args) + { + _appearance.SetData(uid, GasCanisterVisuals.Locked, args.Locked); + } + + /// + /// Check if the canister is locked, playing its sound and popup if so. + /// + /// + /// True if locked, false otherwise. + /// + private bool CheckLocked(EntityUid uid, GasCanisterComponent comp, EntityUid user) + { + if (TryComp(uid, out var lockComp) && lockComp.Locked) + { + _popup.PopupEntity(Loc.GetString("gas-canister-popup-denied"), uid, user); + if (comp.AccessDeniedSound != null) + { + _audio.PlayPvs(comp.AccessDeniedSound, uid); + } + + return true; + } + + return false; + } }