diff --git a/Content.Server/Construction/Completions/AttemptElectrocute.cs b/Content.Server/Construction/Completions/AttemptElectrocute.cs index cabb792552..eb6c100764 100644 --- a/Content.Server/Construction/Completions/AttemptElectrocute.cs +++ b/Content.Server/Construction/Completions/AttemptElectrocute.cs @@ -1,17 +1,24 @@ using Content.Server.Electrocution; using Content.Shared.Construction; -namespace Content.Server.Construction.Completions -{ - [DataDefinition] - public sealed class AttemptElectrocute : IGraphAction - { - public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager) - { - if (userUid == null) - return; +namespace Content.Server.Construction.Completions; - entityManager.EntitySysManager.GetEntitySystem().TryDoElectrifiedAct(uid, userUid.Value); - } +[DataDefinition] +public sealed class AttemptElectrocute : IGraphAction +{ + public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager) + { + if (userUid == null) + return; + + if (!entityManager.TryGetComponent(uid, out var electrified)) + return; + + var currentValue = electrified.Enabled; + electrified.Enabled = true; + + entityManager.EntitySysManager.GetEntitySystem().TryDoElectrifiedAct(uid, userUid.Value, electrified: electrified); + + electrified.Enabled = currentValue; } } diff --git a/Content.Server/Construction/Completions/ChangeWiresPanelSecurityLevel.cs b/Content.Server/Construction/Completions/ChangeWiresPanelSecurityLevel.cs new file mode 100644 index 0000000000..28d7c833d3 --- /dev/null +++ b/Content.Server/Construction/Completions/ChangeWiresPanelSecurityLevel.cs @@ -0,0 +1,27 @@ +using Content.Server.Wires; +using Content.Shared.Construction; +using Content.Shared.Wires; +using JetBrains.Annotations; + +namespace Content.Server.Construction.Completions; + +[UsedImplicitly] +[DataDefinition] +public sealed class ChangeWiresPanelSecurityLevel : IGraphAction +{ + [DataField("level")] + [ValidatePrototypeId] + public string WiresPanelSecurityLevelID = "Level0"; + + public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager) + { + if (WiresPanelSecurityLevelID == null) + return; + + if (entityManager.TryGetComponent(uid, out WiresPanelComponent? wiresPanel) + && entityManager.TrySystem(out WiresSystem? wiresSystem)) + { + wiresSystem.SetWiresPanelSecurityData(uid, wiresPanel, WiresPanelSecurityLevelID); + } + } +} diff --git a/Content.Server/Doors/Systems/AirlockSystem.cs b/Content.Server/Doors/Systems/AirlockSystem.cs index 21e4b71236..f07dd23f4b 100644 --- a/Content.Server/Doors/Systems/AirlockSystem.cs +++ b/Content.Server/Doors/Systems/AirlockSystem.cs @@ -10,180 +10,179 @@ using Content.Shared.Interaction; using Robust.Server.GameObjects; using Content.Shared.Wires; -namespace Content.Server.Doors.Systems +namespace Content.Server.Doors.Systems; + +public sealed class AirlockSystem : SharedAirlockSystem { - public sealed class AirlockSystem : SharedAirlockSystem + [Dependency] private readonly WiresSystem _wiresSystem = default!; + [Dependency] private readonly PowerReceiverSystem _power = default!; + [Dependency] private readonly DoorBoltSystem _bolts = default!; + + public override void Initialize() { - [Dependency] private readonly WiresSystem _wiresSystem = default!; - [Dependency] private readonly PowerReceiverSystem _power = default!; - [Dependency] private readonly DoorBoltSystem _bolts = default!; + base.Initialize(); - public override void Initialize() + SubscribeLocalEvent(OnAirlockInit); + SubscribeLocalEvent(OnSignalReceived); + + SubscribeLocalEvent(OnPowerChanged); + SubscribeLocalEvent(OnStateChanged); + SubscribeLocalEvent(OnBeforeDoorOpened); + SubscribeLocalEvent(OnBeforeDoorDenied); + SubscribeLocalEvent(OnActivate, before: new [] {typeof(DoorSystem)}); + SubscribeLocalEvent(OnGetPryMod); + SubscribeLocalEvent(OnDoorPry); + + } + + private void OnAirlockInit(EntityUid uid, AirlockComponent component, ComponentInit args) + { + if (TryComp(uid, out var receiverComponent)) { - base.Initialize(); - - SubscribeLocalEvent(OnAirlockInit); - SubscribeLocalEvent(OnSignalReceived); - - SubscribeLocalEvent(OnPowerChanged); - SubscribeLocalEvent(OnStateChanged); - SubscribeLocalEvent(OnBeforeDoorOpened); - SubscribeLocalEvent(OnBeforeDoorDenied); - SubscribeLocalEvent(OnActivate, before: new [] {typeof(DoorSystem)}); - SubscribeLocalEvent(OnGetPryMod); - SubscribeLocalEvent(OnDoorPry); - - } - - private void OnAirlockInit(EntityUid uid, AirlockComponent component, ComponentInit args) - { - if (TryComp(uid, out var receiverComponent)) - { - Appearance.SetData(uid, DoorVisuals.Powered, receiverComponent.Powered); - } - } - - private void OnSignalReceived(EntityUid uid, AirlockComponent component, ref SignalReceivedEvent args) - { - if (args.Port == component.AutoClosePort) - { - component.AutoClose = false; - } - } - - private void OnPowerChanged(EntityUid uid, AirlockComponent component, ref PowerChangedEvent args) - { - if (TryComp(uid, out var appearanceComponent)) - { - Appearance.SetData(uid, DoorVisuals.Powered, args.Powered, appearanceComponent); - } - - if (!TryComp(uid, out DoorComponent? door)) - return; - - if (!args.Powered) - { - // stop any scheduled auto-closing - if (door.State == DoorState.Open) - DoorSystem.SetNextStateChange(uid, null); - } - else - { - UpdateAutoClose(uid, door: door); - } - } - - private void OnStateChanged(EntityUid uid, AirlockComponent component, DoorStateChangedEvent args) - { - // TODO move to shared? having this be server-side, but having client-side door opening/closing & prediction - // means that sometimes the panels & bolt lights may be visible despite a door being completely open. - - // Only show the maintenance panel if the airlock is closed - if (TryComp(uid, out var wiresPanel)) - { - _wiresSystem.ChangePanelVisibility(uid, wiresPanel, component.OpenPanelVisible || args.State != DoorState.Open); - } - // If the door is closed, we should look if the bolt was locked while closing - UpdateAutoClose(uid, component); - - // Make sure the airlock auto closes again next time it is opened - if (args.State == DoorState.Closed) - component.AutoClose = true; - } - - /// - /// Updates the auto close timer. - /// - public void UpdateAutoClose(EntityUid uid, AirlockComponent? airlock = null, DoorComponent? door = null) - { - if (!Resolve(uid, ref airlock, ref door)) - return; - - if (door.State != DoorState.Open) - return; - - if (!airlock.AutoClose) - return; - - if (!CanChangeState(uid, airlock)) - return; - - var autoev = new BeforeDoorAutoCloseEvent(); - RaiseLocalEvent(uid, autoev, false); - if (autoev.Cancelled) - return; - - DoorSystem.SetNextStateChange(uid, airlock.AutoCloseDelay * airlock.AutoCloseDelayModifier); - } - - private void OnBeforeDoorOpened(EntityUid uid, AirlockComponent component, BeforeDoorOpenedEvent args) - { - if (!CanChangeState(uid, component)) - args.Cancel(); - } - - protected override void OnBeforeDoorClosed(EntityUid uid, AirlockComponent component, BeforeDoorClosedEvent args) - { - base.OnBeforeDoorClosed(uid, component, args); - - if (args.Cancelled) - return; - - // only block based on bolts / power status when initially closing the door, not when its already - // mid-transition. Particularly relevant for when the door was pried-closed with a crowbar, which bypasses - // the initial power-check. - - if (TryComp(uid, out DoorComponent? door) - && !door.Partial - && !CanChangeState(uid, component)) - { - args.Cancel(); - } - } - - private void OnBeforeDoorDenied(EntityUid uid, AirlockComponent component, BeforeDoorDeniedEvent args) - { - if (!CanChangeState(uid, component)) - args.Cancel(); - } - - private void OnActivate(EntityUid uid, AirlockComponent component, ActivateInWorldEvent args) - { - if (TryComp(uid, out var panel) && panel.Open && - TryComp(args.User, out var actor)) - { - _wiresSystem.OpenUserInterface(uid, actor.PlayerSession); - args.Handled = true; - return; - } - - if (component.KeepOpenIfClicked) - { - // Disable auto close - component.AutoClose = false; - } - } - - private void OnGetPryMod(EntityUid uid, AirlockComponent component, DoorGetPryTimeModifierEvent args) - { - if (_power.IsPowered(uid)) - args.PryTimeModifier *= component.PoweredPryModifier; - } - - private void OnDoorPry(EntityUid uid, AirlockComponent component, BeforeDoorPryEvent args) - { - if (this.IsPowered(uid, EntityManager)) - { - if (HasComp(args.Tool)) - return; - Popup.PopupEntity(Loc.GetString("airlock-component-cannot-pry-is-powered-message"), uid, args.User); - args.Cancel(); - } - } - - public bool CanChangeState(EntityUid uid, AirlockComponent component) - { - return this.IsPowered(uid, EntityManager) && !_bolts.IsBolted(uid); + Appearance.SetData(uid, DoorVisuals.Powered, receiverComponent.Powered); } } + + private void OnSignalReceived(EntityUid uid, AirlockComponent component, ref SignalReceivedEvent args) + { + if (args.Port == component.AutoClosePort) + { + component.AutoClose = false; + } + } + + private void OnPowerChanged(EntityUid uid, AirlockComponent component, ref PowerChangedEvent args) + { + if (TryComp(uid, out var appearanceComponent)) + { + Appearance.SetData(uid, DoorVisuals.Powered, args.Powered, appearanceComponent); + } + + if (!TryComp(uid, out DoorComponent? door)) + return; + + if (!args.Powered) + { + // stop any scheduled auto-closing + if (door.State == DoorState.Open) + DoorSystem.SetNextStateChange(uid, null); + } + else + { + UpdateAutoClose(uid, door: door); + } + } + + private void OnStateChanged(EntityUid uid, AirlockComponent component, DoorStateChangedEvent args) + { + // TODO move to shared? having this be server-side, but having client-side door opening/closing & prediction + // means that sometimes the panels & bolt lights may be visible despite a door being completely open. + + // Only show the maintenance panel if the airlock is closed + if (TryComp(uid, out var wiresPanel)) + { + _wiresSystem.ChangePanelVisibility(uid, wiresPanel, component.OpenPanelVisible || args.State != DoorState.Open); + } + // If the door is closed, we should look if the bolt was locked while closing + UpdateAutoClose(uid, component); + + // Make sure the airlock auto closes again next time it is opened + if (args.State == DoorState.Closed) + component.AutoClose = true; + } + + /// + /// Updates the auto close timer. + /// + public void UpdateAutoClose(EntityUid uid, AirlockComponent? airlock = null, DoorComponent? door = null) + { + if (!Resolve(uid, ref airlock, ref door)) + return; + + if (door.State != DoorState.Open) + return; + + if (!airlock.AutoClose) + return; + + if (!CanChangeState(uid, airlock)) + return; + + var autoev = new BeforeDoorAutoCloseEvent(); + RaiseLocalEvent(uid, autoev, false); + if (autoev.Cancelled) + return; + + DoorSystem.SetNextStateChange(uid, airlock.AutoCloseDelay * airlock.AutoCloseDelayModifier); + } + + private void OnBeforeDoorOpened(EntityUid uid, AirlockComponent component, BeforeDoorOpenedEvent args) + { + if (!CanChangeState(uid, component)) + args.Cancel(); + } + + protected override void OnBeforeDoorClosed(EntityUid uid, AirlockComponent component, BeforeDoorClosedEvent args) + { + base.OnBeforeDoorClosed(uid, component, args); + + if (args.Cancelled) + return; + + // only block based on bolts / power status when initially closing the door, not when its already + // mid-transition. Particularly relevant for when the door was pried-closed with a crowbar, which bypasses + // the initial power-check. + + if (TryComp(uid, out DoorComponent? door) + && !door.Partial + && !CanChangeState(uid, component)) + { + args.Cancel(); + } + } + + private void OnBeforeDoorDenied(EntityUid uid, AirlockComponent component, BeforeDoorDeniedEvent args) + { + if (!CanChangeState(uid, component)) + args.Cancel(); + } + + private void OnActivate(EntityUid uid, AirlockComponent component, ActivateInWorldEvent args) + { + if (TryComp(uid, out var panel) && panel.Open && panel.WiresAccessible + && TryComp(args.User, out var actor)) + { + _wiresSystem.OpenUserInterface(uid, actor.PlayerSession); + args.Handled = true; + return; + } + + if (component.KeepOpenIfClicked) + { + // Disable auto close + component.AutoClose = false; + } + } + + private void OnGetPryMod(EntityUid uid, AirlockComponent component, DoorGetPryTimeModifierEvent args) + { + if (_power.IsPowered(uid)) + args.PryTimeModifier *= component.PoweredPryModifier; + } + + private void OnDoorPry(EntityUid uid, AirlockComponent component, BeforeDoorPryEvent args) + { + if (this.IsPowered(uid, EntityManager)) + { + if (HasComp(args.Tool)) + return; + Popup.PopupEntity(Loc.GetString("airlock-component-cannot-pry-is-powered-message"), uid, args.User); + args.Cancel(); + } + } + + public bool CanChangeState(EntityUid uid, AirlockComponent component) + { + return this.IsPowered(uid, EntityManager) && !_bolts.IsBolted(uid); + } } diff --git a/Content.Server/Electrocution/ElectrocutionSystem.cs b/Content.Server/Electrocution/ElectrocutionSystem.cs index 70f7adfd28..898addd0ff 100644 --- a/Content.Server/Electrocution/ElectrocutionSystem.cs +++ b/Content.Server/Electrocution/ElectrocutionSystem.cs @@ -22,7 +22,6 @@ using Content.Shared.Speech.EntitySystems; using Content.Shared.StatusEffect; using Content.Shared.Stunnable; using Content.Shared.Tag; -using Content.Shared.Weapons.Melee; using Content.Shared.Weapons.Melee.Events; using Robust.Shared.Audio; using Robust.Shared.Map; diff --git a/Content.Server/Tools/Systems/WeldableSystem.cs b/Content.Server/Tools/Systems/WeldableSystem.cs index daaa44836c..e42f1f9104 100644 --- a/Content.Server/Tools/Systems/WeldableSystem.cs +++ b/Content.Server/Tools/Systems/WeldableSystem.cs @@ -1,5 +1,8 @@ using Content.Server.Administration.Logs; +using Content.Server.Construction; using Content.Server.Tools.Components; +using Content.Server.Wires; +using Content.Shared.Construction.Steps; using Content.Shared.Database; using Content.Shared.DoAfter; using Content.Shared.Examine; @@ -7,8 +10,10 @@ using Content.Shared.Interaction; using Content.Shared.Tools; using Content.Shared.Tools.Components; using Content.Shared.Tools.Systems; +using Content.Shared.Wires; using Robust.Shared.Physics; using Robust.Shared.Physics.Systems; +using System.Linq; namespace Content.Server.Tools.Systems; @@ -18,6 +23,7 @@ public sealed class WeldableSystem : EntitySystem [Dependency] private readonly SharedToolSystem _toolSystem = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly ConstructionSystem _construction = default!; public override void Initialize() { @@ -36,6 +42,14 @@ public sealed class WeldableSystem : EntitySystem private void OnInteractUsing(EntityUid uid, WeldableComponent component, InteractUsingEvent args) { + // If any construction graph edges has its conditions meet and requires welding, then this construction takes priority + if (_construction.GetCurrentNode(uid)?.Edges.Any(x => _construction.CheckConditions(uid, x.Conditions) + && x.Steps.Any(y => (y as ToolConstructionGraphStep)?.Tool == "Welding")) == true) + { + args.Handled = false; + return; + } + if (args.Handled) return; diff --git a/Content.Server/Wires/WiresSystem.cs b/Content.Server/Wires/WiresSystem.cs index 8c99852971..26b85e724b 100644 --- a/Content.Server/Wires/WiresSystem.cs +++ b/Content.Server/Wires/WiresSystem.cs @@ -31,6 +31,7 @@ public sealed class WiresSystem : SharedWiresSystem [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly WiresSystem _wiresSystem = default!; // This is where all the wire layouts are stored. [ViewVariables] private readonly Dictionary _layouts = new(); @@ -455,7 +456,7 @@ public sealed class WiresSystem : SharedWiresSystem if (!TryComp(args.Used, out var tool) || !TryComp(uid, out var panel)) return; - if (panel.Open && + if (panel.Open && panel.WiresAccessible && (_toolSystem.HasQuality(args.Used, "Cutting", tool) || _toolSystem.HasQuality(args.Used, "Pulsing", tool))) { @@ -631,6 +632,23 @@ public sealed class WiresSystem : SharedWiresSystem Dirty(component); } + public void SetWiresPanelSecurityData(EntityUid uid, WiresPanelComponent component, string wiresPanelSecurityLevelID) + { + var wiresPanelSecurityLevelPrototype = _protoMan.Index(wiresPanelSecurityLevelID); + + if (wiresPanelSecurityLevelPrototype == null) + return; + + component.WiresAccessible = wiresPanelSecurityLevelPrototype.WiresAccessible; + component.WiresPanelSecurityExamination = wiresPanelSecurityLevelPrototype.Examine; + Dirty(component); + + if (wiresPanelSecurityLevelPrototype?.WiresAccessible == false) + { + _uiSystem.TryCloseAll(uid, WiresUiKey.Key); + } + } + private void UpdateAppearance(EntityUid uid, WiresPanelComponent panel) { if (TryComp(uid, out var appearance)) diff --git a/Content.Shared/Wires/SharedWiresSystem.cs b/Content.Shared/Wires/SharedWiresSystem.cs index d7ddac4de2..78cb298070 100644 --- a/Content.Shared/Wires/SharedWiresSystem.cs +++ b/Content.Shared/Wires/SharedWiresSystem.cs @@ -1,5 +1,4 @@ using Content.Shared.Examine; -using Robust.Shared.GameStates; namespace Content.Shared.Wires; @@ -9,31 +8,22 @@ public abstract class SharedWiresSystem : EntitySystem { base.Initialize(); SubscribeLocalEvent(OnExamine); - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); } private void OnExamine(EntityUid uid, WiresPanelComponent component, ExaminedEvent args) { - args.PushMarkup(Loc.GetString(component.Open - ? "wires-panel-component-on-examine-open" - : "wires-panel-component-on-examine-closed")); - } - - private void OnGetState(EntityUid uid, WiresPanelComponent component, ref ComponentGetState args) - { - args.State = new WiresPanelComponentState + if (!component.Open) { - Open = component.Open, - Visible = component.Visible - }; - } + args.PushMarkup(Loc.GetString("wires-panel-component-on-examine-closed")); + } + else + { + args.PushMarkup(Loc.GetString("wires-panel-component-on-examine-open")); - private void OnHandleState(EntityUid uid, WiresPanelComponent component, ref ComponentHandleState args) - { - if (args.Current is not WiresPanelComponentState state) - return; - component.Open = state.Open; - component.Visible = state.Visible; + if (component?.WiresPanelSecurityExamination != null) + { + args.PushMarkup(Loc.GetString(component.WiresPanelSecurityExamination)); + } + } } -} \ No newline at end of file +} diff --git a/Content.Shared/Wires/WiresPanelComponent.cs b/Content.Shared/Wires/WiresPanelComponent.cs index 668e7f0100..683bd3f830 100644 --- a/Content.Shared/Wires/WiresPanelComponent.cs +++ b/Content.Shared/Wires/WiresPanelComponent.cs @@ -1,23 +1,25 @@ using Robust.Shared.Audio; using Robust.Shared.GameStates; -using Robust.Shared.Serialization; namespace Content.Shared.Wires; [NetworkedComponent, RegisterComponent] [Access(typeof(SharedWiresSystem))] -public sealed class WiresPanelComponent : Component +[AutoGenerateComponentState] +public sealed partial class WiresPanelComponent : Component { /// /// Is the panel open for this entity's wires? /// [DataField("open")] + [AutoNetworkedField] public bool Open; /// /// Should this entity's wires panel be visible at all? /// [ViewVariables] + [AutoNetworkedField] public bool Visible = true; [DataField("screwdriverOpenSound")] @@ -25,11 +27,10 @@ public sealed class WiresPanelComponent : Component [DataField("screwdriverCloseSound")] public SoundSpecifier ScrewdriverCloseSound = new SoundPathSpecifier("/Audio/Machines/screwdriverclose.ogg"); -} -[Serializable, NetSerializable] -public sealed class WiresPanelComponentState : ComponentState -{ - public bool Open; - public bool Visible; + [AutoNetworkedField] + public string? WiresPanelSecurityExamination = default!; + + [AutoNetworkedField] + public bool WiresAccessible = true; } diff --git a/Content.Shared/Wires/WiresPanelSecurityLevelPrototype.cs b/Content.Shared/Wires/WiresPanelSecurityLevelPrototype.cs new file mode 100644 index 0000000000..1fcc982f10 --- /dev/null +++ b/Content.Shared/Wires/WiresPanelSecurityLevelPrototype.cs @@ -0,0 +1,16 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.Wires; + +[Prototype("WiresPanelSecurityLevel")] +public sealed class WiresPanelSecurityLevelPrototype : IPrototype +{ + [IdDataField] + public string ID { get; } = default!; + + [DataField("examine")] + public string? Examine = default!; + + [DataField("wiresAccessible")] + public bool WiresAccessible = true; +} diff --git a/Resources/Locale/en-US/wires/wires_panel-security-levels.ftl b/Resources/Locale/en-US/wires/wires_panel-security-levels.ftl new file mode 100644 index 0000000000..a932877c58 --- /dev/null +++ b/Resources/Locale/en-US/wires/wires_panel-security-levels.ftl @@ -0,0 +1,8 @@ +# Examination for different levels of wiring protection +wires-panel-component-on-examine-security-level1 = There is a steel plate preventing access to the internal wiring. Use a [color=cyan]Crowbar[/color] to remove it. +wires-panel-component-on-examine-security-level2 = A steel plate has been welded to the inside the [color=lightgray]maintenance panel[/color]. Use a [color=cyan]Welder[/color] to free it. +wires-panel-component-on-examine-security-level3 = There is a plasteel plate preventing access to the internal wiring. Use a [color=cyan]Crowbar[/color] to remove it. +wires-panel-component-on-examine-security-level4 = A plasteel plate has been welded to the inside the [color=lightgray]maintenance panel[/color]. Use a [color=cyan]Welder[/color] to free it. +wires-panel-component-on-examine-security-level5 = The inside of the [color=lightgray]maintenance panel[/color] is protected by a security grille. Use [color=cyan]Wirecutters[/color] to remove it. +wires-panel-component-on-examine-security-level6 = A plasteel plate sits within the interior of the [color=lightgray]maintenance panel[/color]. Use a [color=cyan]Crowbar[/color] to remove it. +wires-panel-component-on-examine-security-level7 = A welded plasteel plate protects the interior of the [color=lightgray]maintenance panel[/color]. Use a [color=cyan]Welder[/color] to free it. diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/airlocks.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/airlocks.yml index cdd0ac6a90..0d90cd1e45 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/airlocks.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/airlocks.yml @@ -21,6 +21,8 @@ components: - type: Sprite sprite: Structures/Doors/Airlocks/Standard/atmospherics.rsi + - type: Construction + node: airlockMedSecurity - type: entity parent: Airlock @@ -69,6 +71,8 @@ components: - type: Sprite sprite: Structures/Doors/Airlocks/Standard/command.rsi + - type: Construction + node: airlockMaxSecurity - type: entity parent: Airlock @@ -77,6 +81,8 @@ components: - type: Sprite sprite: Structures/Doors/Airlocks/Standard/security.rsi + - type: Construction + node: airlockMedSecurity - type: entity parent: Airlock @@ -156,6 +162,8 @@ sprite: Structures/Doors/Airlocks/Glass/atmospherics.rsi - type: PaintableAirlock group: Glass + - type: Construction + node: airlockMedSecurity - type: entity parent: AirlockGlass @@ -206,6 +214,8 @@ sprite: Structures/Doors/Airlocks/Glass/command.rsi - type: PaintableAirlock group: Glass + - type: Construction + node: airlockMaxSecurity - type: entity parent: AirlockGlass @@ -216,3 +226,5 @@ sprite: Structures/Doors/Airlocks/Glass/security.rsi - type: PaintableAirlock group: Glass + - type: Construction + node: airlockMedSecurity diff --git a/Resources/Prototypes/Entities/Structures/Doors/wires_panel_security.yml b/Resources/Prototypes/Entities/Structures/Doors/wires_panel_security.yml new file mode 100644 index 0000000000..fb5b762662 --- /dev/null +++ b/Resources/Prototypes/Entities/Structures/Doors/wires_panel_security.yml @@ -0,0 +1,39 @@ +- type: WiresPanelSecurityLevel + id: Level0 + wiresAccessible: true + +- type: WiresPanelSecurityLevel + id: Level1 + examine: wires-panel-component-on-examine-security-level1 + wiresAccessible: false + +- type: WiresPanelSecurityLevel + id: Level2 + examine: wires-panel-component-on-examine-security-level2 + wiresAccessible: false + +- type: WiresPanelSecurityLevel + id: Level3 + examine: wires-panel-component-on-examine-security-level3 + wiresAccessible: false + +- type: WiresPanelSecurityLevel + id: Level4 + examine: wires-panel-component-on-examine-security-level4 + wiresAccessible: false + +- type: WiresPanelSecurityLevel + id: Level5 + examine: wires-panel-component-on-examine-security-level5 + wiresAccessible: false + +- type: WiresPanelSecurityLevel + id: Level6 + examine: wires-panel-component-on-examine-security-level6 + wiresAccessible: false + +- type: WiresPanelSecurityLevel + id: Level7 + examine: wires-panel-component-on-examine-security-level7 + wiresAccessible: false + \ No newline at end of file diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/structures/airlock.yml b/Resources/Prototypes/Recipes/Construction/Graphs/structures/airlock.yml index 2faa18563a..47478ac0fe 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/structures/airlock.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/structures/airlock.yml @@ -86,24 +86,6 @@ - tool: Prying doAfter: 5 - - - node: airlock - entity: Airlock - edges: - - to: wired #TODO DOOR ELECTRONICS. If door electronics ever govern access permissions, this step should probably be further down? It makes it too easy to swap permissions around. See also windoor. - conditions: - - !type:EntityAnchored {} - - !type:DoorWelded {} - - !type:DoorBolted - value: false - - !type:WirePanel {} - - !type:AllWiresCut - completed: - - !type:EmptyAllContainers {} - steps: - - tool: Prying - doAfter: 5 - - node: glassElectronics entity: AirlockAssembly edges: @@ -146,3 +128,217 @@ steps: - tool: Prying doAfter: 2 + + - node: airlock + entity: Airlock + actions: + - !type:ChangeWiresPanelSecurityLevel + level: Level0 + edges: + - to: wired #TODO DOOR ELECTRONICS. If door electronics ever govern access permissions, this step should probably be further down? It makes it too easy to swap permissions around. See also windoor. + conditions: + - !type:EntityAnchored {} + - !type:DoorWelded {} + - !type:DoorBolted + value: false + - !type:WirePanel {} + - !type:AllWiresCut + completed: + - !type:EmptyAllContainers {} + steps: + - tool: Prying + doAfter: 5 + + - to: airlockMedSecurityBreached + conditions: + - !type:WirePanel {} + steps: + - material: Steel + amount: 2 + doAfter: 2 + + - to: airlockHighSecurityBreached + conditions: + - !type:WirePanel {} + steps: + - material: Plasteel + amount: 2 + doAfter: 2 + +## Return node so that removing all internal plating doesn't reset the door + - node: airlockUnsecured + actions: + - !type:ChangeWiresPanelSecurityLevel + level: Level0 + edges: + - to: wired + conditions: + - !type:EntityAnchored {} + - !type:DoorWelded {} + - !type:DoorBolted + value: false + - !type:WirePanel {} + - !type:AllWiresCut + completed: + - !type:EmptyAllContainers {} + steps: + - tool: Prying + doAfter: 5 + + - to: airlockMedSecurityBreached + conditions: + - !type:WirePanel {} + steps: + - material: Steel + amount: 2 + doAfter: 2 + + - to: airlockHighSecurityBreached + conditions: + - !type:WirePanel {} + steps: + - material: Plasteel + amount: 2 + doAfter: 2 + +## Medium security level airlock: a layer of steel plating protects the internal wiring + - node: airlockMedSecurityBreached + actions: + - !type:ChangeWiresPanelSecurityLevel + level: Level1 + edges: + - to: airlockUnsecured + completed: + - !type:GivePrototype + prototype: SheetSteel1 + amount: 2 + conditions: + - !type:WirePanel {} + steps: + - tool: Prying + doAfter: 4 + + - to: airlockMedSecurity + conditions: + - !type:WirePanel {} + steps: + - tool: Welding + doAfter: 3 + + - node: airlockMedSecurity + actions: + - !type:ChangeWiresPanelSecurityLevel + level: Level2 + edges: + - to: airlockMedSecurityBreached + conditions: + - !type:WirePanel {} + steps: + - tool: Welding + doAfter: 10 + +## High security level airlock: a layer of plasteel plating protects the internal wiring + - node: airlockHighSecurityBreached + actions: + - !type:ChangeWiresPanelSecurityLevel + level: Level3 + edges: + - to: airlockUnsecured + completed: + - !type:GivePrototype + prototype: SheetPlasteel1 + amount: 2 + conditions: + - !type:WirePanel {} + steps: + - tool: Prying + doAfter: 4 + + - to: airlockHighSecurity + conditions: + - !type:WirePanel {} + steps: + - tool: Welding + doAfter: 5 + + - node: airlockHighSecurity + actions: + - !type:ChangeWiresPanelSecurityLevel + level: Level4 + edges: + - to: airlockHighSecurityBreached + conditions: + - !type:WirePanel {} + steps: + - tool: Welding + doAfter: 15 + + - to: airlockMaxSecurity + conditions: + - !type:WirePanel {} + steps: + - material: MetalRod + amount: 2 + doAfter: 1 + +## Max security level airlock: an electric grill is added + - node: airlockMaxSecurity + actions: + - !type:ChangeWiresPanelSecurityLevel + level: Level5 + edges: + - to: airlockHighSecurity + completed: + - !type:AttemptElectrocute + - !type:GivePrototype + prototype: PartRodMetal1 + amount: 2 + conditions: + - !type:WirePanel {} + steps: + - tool: Cutting + doAfter: 0.5 + + - to: airlockSuperMaxSecurityBreached + conditions: + - !type:WirePanel {} + steps: + - material: Plasteel + amount: 2 + doAfter: 2 + +## Super max security level airlock: an additional layer of plasteel is added + - node: airlockSuperMaxSecurityBreached + actions: + - !type:ChangeWiresPanelSecurityLevel + level: Level6 + edges: + - to: airlockMaxSecurity + completed: + - !type:GivePrototype + prototype: SheetPlasteel1 + amount: 2 + conditions: + - !type:WirePanel {} + steps: + - tool: Prying + doAfter: 4 + + - to: airlockSuperMaxSecurity + conditions: + - !type:WirePanel {} + steps: + - tool: Welding + doAfter: 5 + + - node: airlockSuperMaxSecurity + actions: + - !type:ChangeWiresPanelSecurityLevel + level: Level7 + edges: + - to: airlockSuperMaxSecurityBreached + conditions: + - !type:WirePanel {} + steps: + - tool: Welding + doAfter: 15