]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Use construction graphs for hacking protections (#20265)
authorchromiumboy <50505512+chromiumboy@users.noreply.github.com>
Fri, 6 Oct 2023 03:15:03 +0000 (22:15 -0500)
committerGitHub <noreply@github.com>
Fri, 6 Oct 2023 03:15:03 +0000 (19:15 -0800)
20 files changed:
Content.Server/Construction/Completions/ChangeWiresPanelSecurityLevel.cs [deleted file]
Content.Server/Construction/Completions/SetWiresPanelSecurity.cs [new file with mode: 0644]
Content.Server/Construction/Conditions/HasTag.cs [new file with mode: 0644]
Content.Server/Construction/ConstructionSystem.Graph.cs
Content.Server/Construction/ConstructionSystem.Interactions.cs
Content.Server/Doors/Systems/AirlockSystem.cs
Content.Server/Wires/WiresSystem.cs
Content.Shared/Construction/ConstructionGraphEdge.cs
Content.Shared/Construction/ConstructionGraphNode.cs
Content.Shared/Wires/SharedWiresSystem.cs
Content.Shared/Wires/WiresPanelComponent.cs
Content.Shared/Wires/WiresPanelSecurityComponent.cs [new file with mode: 0644]
Content.Shared/Wires/WiresPanelSecurityLevelPrototype.cs [deleted file]
Resources/Prototypes/Entities/Structures/Doors/Airlocks/airlocks.yml
Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml
Resources/Prototypes/Entities/Structures/Doors/Airlocks/highsec.yml
Resources/Prototypes/Entities/Structures/Doors/wires_panel_security.yml [deleted file]
Resources/Prototypes/Recipes/Construction/Graphs/structures/airlock.yml
Resources/Prototypes/Recipes/Construction/Graphs/structures/highsec.yml [deleted file]
Resources/Prototypes/tags.yml

diff --git a/Content.Server/Construction/Completions/ChangeWiresPanelSecurityLevel.cs b/Content.Server/Construction/Completions/ChangeWiresPanelSecurityLevel.cs
deleted file mode 100644 (file)
index e484849..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-using Content.Server.Wires;
-using Content.Shared.Construction;
-using Content.Shared.Wires;
-using JetBrains.Annotations;
-
-namespace Content.Server.Construction.Completions;
-
-[UsedImplicitly]
-[DataDefinition]
-public sealed partial class ChangeWiresPanelSecurityLevel : IGraphAction
-{
-    [DataField("level")]
-    [ValidatePrototypeId<WiresPanelSecurityLevelPrototype>]
-    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/Construction/Completions/SetWiresPanelSecurity.cs b/Content.Server/Construction/Completions/SetWiresPanelSecurity.cs
new file mode 100644 (file)
index 0000000..fc71824
--- /dev/null
@@ -0,0 +1,35 @@
+using Content.Shared.Construction;
+using Content.Shared.Wires;
+using JetBrains.Annotations;
+
+namespace Content.Server.Construction.Completions;
+
+/// <summary>
+///     This graph action is used to set values on entities with the <see cref="WiresPanelSecurityComponent"/>
+/// </summary>
+
+[UsedImplicitly]
+[DataDefinition]
+public sealed partial class SetWiresPanelSecurity : IGraphAction
+{
+    /// <summary>
+    ///     Sets the Examine field on the entity's <see cref="WiresPanelSecurityComponent"/>
+    /// </summary>
+    [DataField("examine")]
+    public string Examine = string.Empty;
+
+    /// <summary>
+    ///     Sets the WiresAccessible field on the entity's <see cref="WiresPanelSecurityComponent"/>
+    /// </summary>
+    [DataField("wiresAccessible")]
+    public bool WiresAccessible = true;
+
+    public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager)
+    {
+        if (entityManager.TryGetComponent(uid, out WiresPanelSecurityComponent? _))
+        {
+            var ev = new WiresPanelSecurityEvent(Examine, WiresAccessible);
+            entityManager.EventBus.RaiseLocalEvent(uid, ev);
+        }
+    }
+}
diff --git a/Content.Server/Construction/Conditions/HasTag.cs b/Content.Server/Construction/Conditions/HasTag.cs
new file mode 100644 (file)
index 0000000..b89dbbf
--- /dev/null
@@ -0,0 +1,43 @@
+using Content.Shared.Construction;
+using JetBrains.Annotations;
+using Content.Shared.Doors.Components;
+using Content.Shared.Examine;
+using YamlDotNet.Core.Tokens;
+using Content.Shared.Tag;
+
+namespace Content.Server.Construction.Conditions
+{
+    /// <summary>
+    ///     This condition checks whether if an entity with the <see cref="TagComponent"/> possesses a specific tag
+    /// </summary>
+    [UsedImplicitly]
+    [DataDefinition]
+    public sealed partial class HasTag : IGraphCondition
+    {
+        /// <summary>
+        ///     The tag the entity is being checked for
+        /// </summary>
+        [DataField("tag")]
+        public string Tag { get; private set; }
+
+        public bool Condition(EntityUid uid, IEntityManager entityManager)
+        {
+            if (!entityManager.TrySystem<TagSystem>(out var tagSystem))
+                return false;
+
+            return tagSystem.HasTag(uid, Tag);
+        }
+
+        public bool DoExamine(ExaminedEvent args)
+        {
+            return false;
+        }
+
+        public IEnumerable<ConstructionGuideEntry> GenerateGuideEntry()
+        {
+            yield return new ConstructionGuideEntry()
+            {
+            };
+        }
+    }
+}
index 5d4bcde4cecbd650a7761c9f9ed4a00ec509b966..be8b0e688dd5df11b6fb3abbec33f2171301eaef 100644 (file)
@@ -8,6 +8,7 @@ using Content.Shared.Database;
 using Robust.Server.Containers;
 using Robust.Shared.Containers;
 using Robust.Shared.Prototypes;
+using System.Linq;
 
 namespace Content.Server.Construction
 {
@@ -298,9 +299,23 @@ namespace Content.Server.Construction
                 throw new Exception("Missing construction components");
             }
 
+            // Exit if the new entity's prototype is the same as the original, or the prototype is invalid
             if (newEntity == metaData.EntityPrototype?.ID || !_prototypeManager.HasIndex<EntityPrototype>(newEntity))
                 return null;
 
+            // [Optional] Exit if the new entity's prototype is a parent of the original
+            // E.g., if an entity with the 'AirlockCommand' prototype was to be replaced with a new entity that 
+            // had the 'Airlock' prototype, and DoNotReplaceInheritingEntities was true, the code block would 
+            // exit here because 'AirlockCommand' is derived from 'Airlock'
+            if (GetCurrentNode(uid, construction)?.DoNotReplaceInheritingEntities == true &&
+                metaData.EntityPrototype?.ID != null)
+            {
+                var parents = _prototypeManager.EnumerateParents<EntityPrototype>(metaData.EntityPrototype.ID)?.ToList();
+
+                if (parents != null && parents.Any(x => x.ID == newEntity))
+                    return null;
+            }
+
             // Optional resolves.
             Resolve(uid, ref containerManager, false);
 
index e2e99ad74eaaf99af1ac5d427041079ceb201d42..21daabdb5da6ca63ab0c1baff143d92ec0fd00ee 100644 (file)
@@ -12,6 +12,7 @@ using Content.Shared.Interaction;
 using Content.Shared.Prying.Systems;
 using Content.Shared.Radio.EntitySystems;
 using Content.Shared.Tools.Components;
+using Content.Shared.Tools.Systems;
 using Robust.Shared.Containers;
 using Robust.Shared.Map;
 using Robust.Shared.Utility;
@@ -38,7 +39,7 @@ namespace Content.Server.Construction
 
             // Event handling. Add your subscriptions here! Just make sure they're all handled by EnqueueEvent.
             SubscribeLocalEvent<ConstructionComponent, InteractUsingEvent>(EnqueueEvent,
-                new []{typeof(AnchorableSystem), typeof(PryingSystem) },
+                new []{typeof(AnchorableSystem), typeof(PryingSystem), typeof(WeldableSystem)},
                 new []{typeof(EncryptionKeySystem)});
             SubscribeLocalEvent<ConstructionComponent, OnTemperatureChangeEvent>(EnqueueEvent);
             SubscribeLocalEvent<ConstructionComponent, PartAssemblyPartInsertedEvent>(EnqueueEvent);
index 67f732f28e413dd2fb3780d7466debed527579df..06fdac45d8f77f6e942de58b59c6e4ebeb0b1abc 100644 (file)
@@ -18,7 +18,6 @@ public sealed class AirlockSystem : SharedAirlockSystem
     [Dependency] private readonly WiresSystem _wiresSystem = default!;
     [Dependency] private readonly PowerReceiverSystem _power = default!;
     [Dependency] private readonly DoorBoltSystem _bolts = default!;
-    [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
 
     public override void Initialize()
     {
@@ -153,8 +152,8 @@ public sealed class AirlockSystem : SharedAirlockSystem
     {
         if (TryComp<WiresPanelComponent>(uid, out var panel) &&
             panel.Open &&
-            _prototypeManager.TryIndex<WiresPanelSecurityLevelPrototype>(panel.CurrentSecurityLevelID, out var securityLevelPrototype) &&
-            securityLevelPrototype.WiresAccessible &&
+            TryComp<WiresPanelSecurityComponent>(uid, out var wiresPanelSecurity) &&
+            wiresPanelSecurity.WiresAccessible &&
             TryComp<ActorComponent>(args.User, out var actor))
         {
             _wiresSystem.OpenUserInterface(uid, actor.PlayerSession);
index e9522485ca1bb337453398b13dd7696edea40bcd..37b6282bb646ab348d22262a0740a5884b60e8ac 100644 (file)
@@ -2,6 +2,8 @@ using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using System.Threading;
 using Content.Server.Administration.Logs;
+using Content.Server.Construction;
+using Content.Server.Construction.Components;
 using Content.Server.Power.Components;
 using Content.Server.UserInterface;
 using Content.Shared.Database;
@@ -33,6 +35,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 ConstructionSystem _construction = default!;
 
     // This is where all the wire layouts are stored.
     [ViewVariables] private readonly Dictionary<string, WireLayout> _layouts = new();
@@ -58,6 +61,7 @@ public sealed class WiresSystem : SharedWiresSystem
         SubscribeLocalEvent<WiresComponent, WireDoAfterEvent>(OnDoAfter);
         SubscribeLocalEvent<ActivatableUIRequiresPanelComponent, ActivatableUIOpenAttemptEvent>(OnAttemptOpenActivatableUI);
         SubscribeLocalEvent<ActivatableUIRequiresPanelComponent, PanelChangedEvent>(OnActivatableUIPanelChanged);
+        SubscribeLocalEvent<WiresPanelSecurityComponent, WiresPanelSecurityEvent>(SetWiresPanelSecurity);
     }
     private void SetOrCreateWireLayout(EntityUid uid, WiresComponent? wires = null)
     {
@@ -459,8 +463,8 @@ public sealed class WiresSystem : SharedWiresSystem
             return;
 
         if (panel.Open &&
-            _protoMan.TryIndex<WiresPanelSecurityLevelPrototype>(panel.CurrentSecurityLevelID, out var securityLevelPrototype) &&
-            securityLevelPrototype.WiresAccessible &&
+            TryComp<WiresPanelSecurityComponent>(uid, out var wiresPanelSecurity) &&
+            wiresPanelSecurity.WiresAccessible &&
             (_toolSystem.HasQuality(args.Used, "Cutting", tool) ||
             _toolSystem.HasQuality(args.Used, "Pulsing", tool)))
         {
@@ -526,6 +530,14 @@ public sealed class WiresSystem : SharedWiresSystem
         if (component.WireSeed == 0)
             component.WireSeed = _random.Next(1, int.MaxValue);
 
+        // Update the construction graph to make sure that it starts on the node specified by WiresPanelSecurityComponent
+        if (TryComp<WiresPanelSecurityComponent>(uid, out var wiresPanelSecurity) &&
+            !string.IsNullOrEmpty(wiresPanelSecurity.SecurityLevel) &&
+            TryComp<ConstructionComponent>(uid, out var construction))
+        {
+            _construction.ChangeNode(uid, null, wiresPanelSecurity.SecurityLevel, true, construction);
+        }
+
         UpdateUserInterface(uid);
     }
     #endregion
@@ -656,13 +668,14 @@ public sealed class WiresSystem : SharedWiresSystem
         RaiseLocalEvent(uid, ref ev);
     }
 
-    public void SetWiresPanelSecurityData(EntityUid uid, WiresPanelComponent component, string wiresPanelSecurityLevelID)
+    public void SetWiresPanelSecurity(EntityUid uid, WiresPanelSecurityComponent component, WiresPanelSecurityEvent args)
     {
-        component.CurrentSecurityLevelID = wiresPanelSecurityLevelID;
+        component.Examine = args.Examine;
+        component.WiresAccessible = args.WiresAccessible;
+
         Dirty(uid, component);
 
-        if (_protoMan.TryIndex<WiresPanelSecurityLevelPrototype>(component.CurrentSecurityLevelID, out var securityLevelPrototype) &&
-            securityLevelPrototype.WiresAccessible)
+        if (!args.WiresAccessible)
         {
             _uiSystem.TryCloseAll(uid, WiresUiKey.Key);
         }
index 6ac75717430121e6f0beac345af62c208f756d23..5166da94207d109672715569602da1e2f1cc6b48 100644 (file)
@@ -1,4 +1,4 @@
-using Content.Shared.Construction.Steps;
+using Content.Shared.Construction.Steps;
 
 namespace Content.Shared.Construction
 {
index 265463c2431e4658a89008814689137d08c91e28..fd70569e9daae4658dbc4a1c4d49813554e5e03e 100644 (file)
@@ -1,4 +1,4 @@
-using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics.CodeAnalysis;
 using Content.Shared.Construction.NodeEntities;
 using Content.Shared.Construction.Serialization;
 using Robust.Shared.Prototypes;
@@ -31,6 +31,20 @@ namespace Content.Shared.Construction
         [DataField("entity", customTypeSerializer: typeof(GraphNodeEntitySerializer), serverOnly:true)]
         public IGraphNodeEntity Entity { get; private set; } = new NullNodeEntity();
 
+        /// <summary>
+        ///     Ignore requests to change the entity if the entity's current prototype inherits from specified replacement 
+        /// </summary>
+        /// <remarks>
+        ///     When this bool is true and a construction node specifies that the current entity should be replaced with a new entity, if the 
+        ///     current entity has an entity prototype which inherits from the replacement entity prototype, entity replacement will not occur.
+        ///     E.g., if an entity with the 'AirlockCommand' prototype was to be replaced with a new entity that had the 'Airlock' prototype, 
+        ///     and 'DoNotReplaceInheritingEntities' was true, the entity would not be replaced because 'AirlockCommand' is derived from 'Airlock' 
+        ///     This will largely be used for construction graphs which have removeable upgrades, such as hacking protections for airlocks,
+        ///     so that the upgrades can be removed and you can return to the last primary construction step without replacing the entity
+        /// </remarks>
+        [DataField("doNotReplaceInheritingEntities")]
+        public bool DoNotReplaceInheritingEntities = false;
+
         public ConstructionGraphEdge? GetEdge(string target)
         {
             foreach (var edge in _edges)
index 055827e8b1dd288225809f3266b274957d4710a1..50465537e8ccaa90ea343dae58edd72ca2048de1 100644 (file)
@@ -6,14 +6,11 @@ namespace Content.Shared.Wires;
 
 public abstract class SharedWiresSystem : EntitySystem
 {
-    [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
-
     public override void Initialize()
     {
         base.Initialize();
 
         SubscribeLocalEvent<WiresPanelComponent, ExaminedEvent>(OnExamine);
-        SubscribeLocalEvent<WiresPanelComponent, WeldableAttemptEvent>(OnWeldableAttempt);
     }
 
     private void OnExamine(EntityUid uid, WiresPanelComponent component, ExaminedEvent args)
@@ -26,21 +23,11 @@ public abstract class SharedWiresSystem : EntitySystem
         {
             args.PushMarkup(Loc.GetString("wires-panel-component-on-examine-open"));
 
-            if (_prototypeManager.TryIndex<WiresPanelSecurityLevelPrototype>(component.CurrentSecurityLevelID, out var securityLevelPrototype) &&
-                securityLevelPrototype.Examine != null)
+            if (TryComp<WiresPanelSecurityComponent>(uid, out var wiresPanelSecurity) &&
+                wiresPanelSecurity.Examine != null)
             {
-                args.PushMarkup(Loc.GetString(securityLevelPrototype.Examine));
+                args.PushMarkup(Loc.GetString(wiresPanelSecurity.Examine));
             }
         }
     }
-
-    private void OnWeldableAttempt(EntityUid uid, WiresPanelComponent component, WeldableAttemptEvent args)
-    {
-        if (component.Open &&
-            _prototypeManager.TryIndex<WiresPanelSecurityLevelPrototype>(component.CurrentSecurityLevelID, out var securityLevelPrototype) &&
-            !securityLevelPrototype.WeldingAllowed)
-        {
-            args.Cancel();
-        }
-    }
 }
index adc9d9a5f097f77133af93d2c35bd210a9950aa8..1162d0503386219d9f4f22124faf4a7441815c3d 100644 (file)
@@ -27,14 +27,6 @@ public sealed partial class WiresPanelComponent : Component
 
     [DataField("screwdriverCloseSound")]
     public SoundSpecifier ScrewdriverCloseSound = new SoundPathSpecifier("/Audio/Machines/screwdriverclose.ogg");
-
-    /// <summary>
-    ///     This prototype describes the current security features of the wire panel
-    /// </summary>
-    [DataField("securityLevel")]
-    [ValidatePrototypeId<WiresPanelSecurityLevelPrototype>]
-    [AutoNetworkedField]
-    public string CurrentSecurityLevelID = "Level0";
 }
 
 /// <summary>
diff --git a/Content.Shared/Wires/WiresPanelSecurityComponent.cs b/Content.Shared/Wires/WiresPanelSecurityComponent.cs
new file mode 100644 (file)
index 0000000..e894f1f
--- /dev/null
@@ -0,0 +1,50 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Wires;
+
+/// <summary>
+///     Allows hacking protections to a be added to an entity.
+///     These safeguards are determined via a construction graph,
+///     so the entity requires <cref="ConstructionComponent"/> for this to function 
+/// </summary>
+[NetworkedComponent, RegisterComponent]
+[Access(typeof(SharedWiresSystem))]
+[AutoGenerateComponentState]
+public sealed partial class WiresPanelSecurityComponent : Component
+{
+    /// <summary>
+    ///     A verbal description of the wire panel's current security level
+    /// </summary>
+    [DataField("examine")]
+    [AutoNetworkedField]
+    public string? Examine = default!;
+
+    /// <summary>
+    ///     Determines whether the wiring is accessible to hackers or not
+    /// </summary>
+    [DataField("wiresAccessible")]
+    [AutoNetworkedField]
+    public bool WiresAccessible = true;
+
+    /// <summary>
+    ///     Name of the construction graph node that the entity will start on
+    /// </summary>
+    [DataField("securityLevel")]
+    [AutoNetworkedField]
+    public string SecurityLevel = string.Empty;
+}
+
+/// <summary>
+///     This event gets raised when security settings on a wires panel change
+/// </summary>
+public sealed class WiresPanelSecurityEvent : EntityEventArgs
+{
+    public readonly string? Examine;
+    public readonly bool WiresAccessible;
+
+    public WiresPanelSecurityEvent(string? examine, bool wiresAccessible)
+    {
+        Examine = examine;
+        WiresAccessible = wiresAccessible;
+    }
+}
diff --git a/Content.Shared/Wires/WiresPanelSecurityLevelPrototype.cs b/Content.Shared/Wires/WiresPanelSecurityLevelPrototype.cs
deleted file mode 100644 (file)
index 8ddc8ee..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.Wires;
-
-[Prototype("WiresPanelSecurityLevel")]
-public sealed class WiresPanelSecurityLevelPrototype : IPrototype
-{
-    [IdDataField]
-    public string ID { get; private set; } = default!;
-
-    /// <summary>
-    ///     A verbal description of the wire panel's current security level
-    /// </summary>
-    [DataField("examine")]
-    public string? Examine = default!;
-
-    /// <summary>
-    ///     Determines whether the wiring is accessible to hackers or not
-    /// </summary>
-    [DataField("wiresAccessible")]
-    public bool WiresAccessible = true;
-
-    /// <summary>
-    ///     Determines whether the device can be welded shut or not
-    /// </summary>
-    /// <remarks>
-    ///     Should be set false when you need to weld/unweld something to/from the wire panel
-    /// </remarks>
-    [DataField("weldingAllowed")]
-    public bool WeldingAllowed = true;
-}
index f445163257d445dffe3ccd96f3aea81f0c3b3c89..940e2e8b36cb521075e705b9a21374a8cc3a0ee3 100644 (file)
   components:
   - type: Sprite
     sprite: Structures/Doors/Airlocks/Standard/command.rsi
-  - type: WiresPanel
-    securityLevel: Level2
-  - type: Construction
-    node: airlockMedSecurity
+  - type: WiresPanelSecurity
+    securityLevel: medSecurity
 
 - type: entity
   parent: Airlock
     group: Glass
   - type: RadiationBlocker
     resistance: 2
-
+  - type: Tag
+    tags:
+      - GlassAirlock
+      # This tag is used to nagivate the Airlock construction graph. It's needed because the construction graph is shared between Airlock, AirlockGlass, and HighSecDoor
 - type: entity
   parent: AirlockGlass
   id: AirlockEngineeringGlass
     sprite: Structures/Doors/Airlocks/Glass/command.rsi
   - type: PaintableAirlock
     group: Glass
-  - type: WiresPanel
-    securityLevel: Level2
-  - type: Construction
-    node: glassAirlockMedSecurity
+  - type: WiresPanelSecurity
+    securityLevel: medSecurity
 
 - type: entity
   parent: AirlockGlass
index f40ef4ea84745cce4f3b20bc3c4d533e60a2b2a1..51d3cfdda0984842954d80104710983202e0d0de 100644 (file)
@@ -74,6 +74,7 @@
     enabled: false
     usesApcPower: true
   - type: WiresPanel
+  - type: WiresPanelSecurity
   - type: Wires
     BoardName: wires-board-name-airlock
     LayoutId: Airlock
   - type: AccessReader
   - type: StaticPrice
     price: 150
+  - type: Tag
+    tags:
+      - Airlock 
+      # This tag is used to nagivate the Airlock construction graph. It's needed because the construction graph is shared between Airlock, AirlockGlass, and HighSecDoor
   placement:
     mode: SnapgridCenter
+
index 80194a48cdfce7e6b04892b6b0f61552373d3718..c653d2d0100f1490eb3da25821ee657a44b3e78a 100644 (file)
@@ -67,7 +67,8 @@
     enabled: false\r
     usesApcPower: true\r
   - type: WiresPanel\r
-    securityLevel: Level5\r
+  - type: WiresPanelSecurity\r
+    securityLevel: maxSecurity\r
   - type: Wires\r
     BoardName: wires-board-name-highsec\r
     LayoutId: HighSec\r
@@ -94,5 +95,9 @@
     key: walls\r
     mode: NoSprite\r
   - type: Construction\r
-    graph: HighSecDoor\r
-    node: maxSecurity\r
+    graph: Airlock\r
+    node: highSecDoor\r
+  - type: Tag\r
+    tags:\r
+      - HighSecDoor\r
+      # This tag is used to nagivate the Airlock construction graph. It's needed because this construction graph is shared between Airlock, AirlockGlass, and HighSecDoor
\ No newline at end of file
diff --git a/Resources/Prototypes/Entities/Structures/Doors/wires_panel_security.yml b/Resources/Prototypes/Entities/Structures/Doors/wires_panel_security.yml
deleted file mode 100644 (file)
index 4a42ed3..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-- type: WiresPanelSecurityLevel
-  id: Level0
-  wiresAccessible: true
-  
-- type: WiresPanelSecurityLevel
-  id: Level1
-  examine: wires-panel-component-on-examine-security-level1
-  wiresAccessible: false
-  weldingAllowed: false
-  
-- type: WiresPanelSecurityLevel
-  id: Level2
-  examine: wires-panel-component-on-examine-security-level2
-  wiresAccessible: false
-  weldingAllowed: false
-  
-- type: WiresPanelSecurityLevel
-  id: Level3
-  examine: wires-panel-component-on-examine-security-level3
-  wiresAccessible: false
-  weldingAllowed: false
-  
-- type: WiresPanelSecurityLevel
-  id: Level4
-  examine: wires-panel-component-on-examine-security-level4
-  wiresAccessible: false
-  weldingAllowed: 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
-  weldingAllowed: false
-  
-- type: WiresPanelSecurityLevel
-  id: Level7
-  examine: wires-panel-component-on-examine-security-level7
-  wiresAccessible: false
-  weldingAllowed: false
-  
\ No newline at end of file
index 3d7e45873185f87bf33240e532904c616bc3800b..4ddeb3851960d0fb15f2e49bb6858664317718e8 100644 (file)
       - tool: Prying
         doAfter: 5
 
+## Glass airlock
   - node: glassAirlock
     entity: AirlockGlass
+    doNotReplaceInheritingEntities: true
     actions:
-    - !type:ChangeWiresPanelSecurityLevel
-      level: Level0
+    - !type:SetWiresPanelSecurity
+      wiresAccessible: true
+      weldingAllowed: true
     edges:
     - to: glassElectronics
       conditions:
       - tool: Prying
         doAfter: 2
         
-    - to: glassAirlockMedSecurityBreached
+    - to: medSecurityUnfinished
       conditions:
       - !type:WirePanel {}
       steps:
         amount: 2
         doAfter: 2
     
-    - to: glassAirlockHighSecurityBreached
+    - to: highSecurityUnfinished
       conditions:
       - !type:WirePanel {}
       steps:
       - material: Plasteel
         amount: 2
         doAfter: 2
-
-## Return node so that removing all internal plating doesn't reset the door
-  - node: glassAirlockUnsecured    
+        
+## Standard airlock
+  - node: airlock
+    entity: Airlock
+    doNotReplaceInheritingEntities: true
     actions:
-    - !type:ChangeWiresPanelSecurityLevel
-      level: Level0
+    - !type:SetWiresPanelSecurity
+      wiresAccessible: true
+      weldingAllowed: true
     edges:
-    - to: glassElectronics
+    - to: wired
       conditions:
       - !type:EntityAnchored {}
       - !type:DoorWelded {}
       - !type:WirePanel {}
       - !type:AllWiresCut
       completed:
-      - !type:SpawnPrototype
-        prototype: SheetRGlass1
-        amount: 1
+      - !type:EmptyAllContainers {}
       steps:
       - tool: Prying
-        doAfter: 2
+        doAfter: 5
         
-    - to: glassAirlockMedSecurityBreached 
+    - to: medSecurityUnfinished
       conditions:
       - !type:WirePanel {}
       steps:
       - material: Steel
         amount: 2
         doAfter: 2
-        
-    - to: glassAirlockHighSecurityBreached
+    
+    - to: highSecurityUnfinished
       conditions:
       - !type:WirePanel {}
       steps:
         amount: 2
         doAfter: 2
 
-## Medium security level airlock: a layer of steel plating protects the internal wiring
-  - node: glassAirlockMedSecurityBreached
+## High security door
+  - node: highSecDoor
     actions:
-      - !type:ChangeWiresPanelSecurityLevel
-        level: Level1    
-    edges:
-    - to: glassAirlockUnsecured 
-      completed:
-      - !type:GivePrototype
-        prototype: SheetSteel1
-        amount: 2
+    - !type:SetWiresPanelSecurity
+      wiresAccessible: true
+      weldingAllowed: true
+    edges:   
+    - to: medSecurityUnfinished
       conditions:
       - !type:WirePanel {}
       steps:
-      - tool: Prying
-        doAfter: 4
+      - material: Steel
+        amount: 2
+        doAfter: 2
     
-    - to: glassAirlockMedSecurity 
-      conditions:  
-      - !type:WirePanel {}
-      steps:
-      - tool: Welding
-        doAfter: 3
-      
-  - node: glassAirlockMedSecurity
-    actions:
-      - !type:ChangeWiresPanelSecurityLevel
-        level: Level2
-    edges:
-    - to: glassAirlockMedSecurityBreached 
+    - to: highSecurityUnfinished
       conditions:
       - !type:WirePanel {}
       steps:
-      - tool: Welding
-        doAfter: 10
+      - material: Plasteel
+        amount: 2
+        doAfter: 2
 
-## High security level airlock: a layer of plasteel plating protects the internal wiring
-  - node: glassAirlockHighSecurityBreached
+## Medium security level door: a layer of steel plating protects the internal wiring
+  - node: medSecurityUnfinished
     actions:
-      - !type:ChangeWiresPanelSecurityLevel
-        level: Level3   
+    - !type:SetWiresPanelSecurity
+      examine: wires-panel-component-on-examine-security-level1
+      wiresAccessible: false
+      weldingAllowed: false
     edges:
-    - to: glassAirlockUnsecured 
+    - to: glassAirlock 
       completed:
       - !type:GivePrototype
-        prototype: SheetPlasteel1
+        prototype: SheetSteel1
         amount: 2
       conditions:
       - !type:WirePanel {}
+      - !type:HasTag
+        tag: GlassAirlock
       steps:
       - tool: Prying
         doAfter: 4
-    
-    - to: glassAirlockHighSecurity 
-      conditions:  
-      - !type:WirePanel {}
-      steps:
-      - tool: Welding
-        doAfter: 5
-      
-  - node: glassAirlockHighSecurity
-    actions:
-      - !type:ChangeWiresPanelSecurityLevel
-        level: Level4
-    edges:
-    - to: glassAirlockHighSecurityBreached
-      conditions:
-      - !type:WirePanel {}
-      steps:
-      - tool: Welding
-        doAfter: 15
-    
-    - to: glassAirlockMaxSecurity
-      conditions:
-      - !type:WirePanel {}
-      steps:     
-      - material: MetalRod
-        amount: 2
-        doAfter: 1
-
-## Max security level airlock: an electric grill is added        
-  - node: glassAirlockMaxSecurity
-    actions:
-      - !type:ChangeWiresPanelSecurityLevel
-        level: Level5
-    edges:
-    - to: glassAirlockHighSecurity 
+        
+    - to: airlock 
       completed:
-      - !type:AttemptElectrocute
       - !type:GivePrototype
-        prototype: PartRodMetal1
+        prototype: SheetSteel1
         amount: 2
-      conditions:  
-      - !type:WirePanel {}
-      steps:
-      - tool: Cutting
-        doAfter: 0.5 
-
-    - to: glassAirlockSuperMaxSecurityBreached
       conditions:
       - !type:WirePanel {}
-      steps:     
-      - material: Plasteel
-        amount: 2
-        doAfter: 2
-
-## Super max security level airlock: an additional layer of plasteel is added     
-  - node: glassAirlockSuperMaxSecurityBreached
-    actions:
-      - !type:ChangeWiresPanelSecurityLevel
-        level: Level6
-    edges:
-    - to: glassAirlockMaxSecurity 
+      - !type:HasTag
+        tag: Airlock
+      steps:
+      - tool: Prying
+        doAfter: 4
+        
+    - to: highSecDoor 
       completed:
       - !type:GivePrototype
-        prototype: SheetPlasteel1
+        prototype: SheetSteel1
         amount: 2
       conditions:
       - !type:WirePanel {}
+      - !type:HasTag
+        tag: HighSecDoor
       steps:
       - tool: Prying
         doAfter: 4
     
-    - to: glassAirlockSuperMaxSecurity 
+    - to: medSecurity 
       conditions:  
       - !type:WirePanel {}
       steps:
       - tool: Welding
-        doAfter: 5
+        doAfter: 3
       
-  - node: glassAirlockSuperMaxSecurity
+  - node: medSecurity
     actions:
-      - !type:ChangeWiresPanelSecurityLevel
-        level: Level7
+    - !type:SetWiresPanelSecurity
+      examine: wires-panel-component-on-examine-security-level2
+      wiresAccessible: false
+      weldingAllowed: false
     edges:
-    - to: glassAirlockSuperMaxSecurityBreached 
+    - to: medSecurityUnfinished 
       conditions:
       - !type:WirePanel {}
       steps:
       - tool: Welding
-        doAfter: 15
+        doAfter: 10
 
-  - node: airlock
-    entity: Airlock
+## High security level door: a layer of plasteel plating protects the internal wiring
+  - node: highSecurityUnfinished
     actions:
-    - !type:ChangeWiresPanelSecurityLevel
-      level: Level0
+    - !type:SetWiresPanelSecurity
+      examine: wires-panel-component-on-examine-security-level3
+      wiresAccessible: false
+      weldingAllowed: false
     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
+    - to: glassAirlock 
       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
+      - !type:GivePrototype
+        prototype: SheetPlasteel1
         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 {}
+      - !type:HasTag
+        tag: GlassAirlock
       steps:
       - tool: Prying
-        doAfter: 5
-        
-    - to: airlockMedSecurityBreached 
-      conditions:
-      - !type:WirePanel {}
-      steps:
-      - material: Steel
-        amount: 2
-        doAfter: 2
+        doAfter: 4
         
-    - 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 
+    - to: airlock 
       completed:
       - !type:GivePrototype
-        prototype: SheetSteel1
+        prototype: SheetPlasteel1
         amount: 2
       conditions:
       - !type:WirePanel {}
+      - !type:HasTag
+        tag: Airlock
       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 
+        
+    - to: highSecDoor 
       completed:
       - !type:GivePrototype
         prototype: SheetPlasteel1
         amount: 2
       conditions:
       - !type:WirePanel {}
+      - !type:HasTag
+        tag: HighSecDoor
       steps:
       - tool: Prying
         doAfter: 4
     
-    - to: airlockHighSecurity 
+    - to: highSecurity 
       conditions:  
       - !type:WirePanel {}
       steps:
       - tool: Welding
         doAfter: 5
       
-  - node: airlockHighSecurity
+  - node: highSecurity
     actions:
-      - !type:ChangeWiresPanelSecurityLevel
-        level: Level4
+    - !type:SetWiresPanelSecurity
+      examine: wires-panel-component-on-examine-security-level4
+      wiresAccessible: false
+      weldingAllowed: false
     edges:
-    - to: airlockHighSecurityBreached
+    - to: highSecurityUnfinished
       conditions:
       - !type:WirePanel {}
       steps:
       - tool: Welding
         doAfter: 15
     
-    - to: airlockMaxSecurity
+    - to: maxSecurity
       conditions:
       - !type:WirePanel {}
       steps:     
         amount: 2
         doAfter: 1
 
-## Max security level airlock: an electric grill is added        
-  - node: airlockMaxSecurity
+## Max security level door: an electric grill is added        
+  - node: maxSecurity
     actions:
-      - !type:ChangeWiresPanelSecurityLevel
-        level: Level5
+    - !type:SetWiresPanelSecurity
+      examine: wires-panel-component-on-examine-security-level5
+      wiresAccessible: false
+      weldingAllowed: true
     edges:
-    - to: airlockHighSecurity 
+    - to: highSecurity 
       completed:
       - !type:AttemptElectrocute
       - !type:GivePrototype
       - tool: Cutting
         doAfter: 0.5 
 
-    - to: airlockSuperMaxSecurityBreached
+    - to: superMaxSecurityUnfinished
       conditions:
       - !type:WirePanel {}
       steps:     
         amount: 2
         doAfter: 2
 
-## Super max security level airlock: an additional layer of plasteel is added     
-  - node: airlockSuperMaxSecurityBreached
+## Super max security level door: an additional layer of plasteel is added     
+  - node: superMaxSecurityUnfinished
     actions:
-      - !type:ChangeWiresPanelSecurityLevel
-        level: Level6
+    - !type:SetWiresPanelSecurity
+      examine: wires-panel-component-on-examine-security-level6
+      wiresAccessible: false
+      weldingAllowed: false
     edges:
-    - to: airlockMaxSecurity 
+    - to: maxSecurity 
       completed:
       - !type:GivePrototype
         prototype: SheetPlasteel1
       - tool: Prying
         doAfter: 4
     
-    - to: airlockSuperMaxSecurity 
+    - to: superMaxSecurity 
       conditions:  
       - !type:WirePanel {}
       steps:
       - tool: Welding
         doAfter: 5
       
-  - node: airlockSuperMaxSecurity
+  - node: superMaxSecurity
     actions:
-      - !type:ChangeWiresPanelSecurityLevel
-        level: Level7
+    - !type:SetWiresPanelSecurity
+      examine: wires-panel-component-on-examine-security-level7
+      wiresAccessible: false  
+      weldingAllowed: false
     edges:
-    - to: airlockSuperMaxSecurityBreached 
+    - to: superMaxSecurityUnfinished 
       conditions:
       - !type:WirePanel {}
       steps:
       - tool: Welding
-        doAfter: 15
+        doAfter: 15        
diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/structures/highsec.yml b/Resources/Prototypes/Recipes/Construction/Graphs/structures/highsec.yml
deleted file mode 100644 (file)
index bf210ad..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-- type: constructionGraph
-  id: HighSecDoor
-  start: start
-  graph:
-  - node: start
-    actions:
-    - !type:ChangeWiresPanelSecurityLevel
-      level: Level0
-    edges:
-    - to: medSecurityBreached
-      conditions:
-      - !type:WirePanel {}
-      steps:
-      - material: Steel
-        amount: 2
-        doAfter: 2
-    
-    - to: highSecurityBreached
-      conditions:
-      - !type:WirePanel {}
-      steps:
-      - material: Plasteel
-        amount: 2
-        doAfter: 2
-
-## Medium security level door: a layer of steel plating protects the internal wiring
-  - node: medSecurityBreached
-    actions:
-      - !type:ChangeWiresPanelSecurityLevel
-        level: Level1    
-    edges:
-    - to: start 
-      completed:
-      - !type:GivePrototype
-        prototype: SheetSteel1
-        amount: 2
-      conditions:
-      - !type:WirePanel {}
-      steps:
-      - tool: Prying
-        doAfter: 4
-    
-    - to: medSecurity 
-      conditions:  
-      - !type:WirePanel {}
-      steps:
-      - tool: Welding
-        doAfter: 3
-      
-  - node: medSecurity
-    actions:
-      - !type:ChangeWiresPanelSecurityLevel
-        level: Level2
-    edges:
-    - to: medSecurityBreached 
-      conditions:
-      - !type:WirePanel {}
-      steps:
-      - tool: Welding
-        doAfter: 10
-
-## High security level door: a layer of plasteel plating protects the internal wiring
-  - node: highSecurityBreached
-    actions:
-      - !type:ChangeWiresPanelSecurityLevel
-        level: Level3   
-    edges:
-    - to: start 
-      completed:
-      - !type:GivePrototype
-        prototype: SheetPlasteel1
-        amount: 2
-      conditions:
-      - !type:WirePanel {}
-      steps:
-      - tool: Prying
-        doAfter: 4
-    
-    - to: highSecurity 
-      conditions:  
-      - !type:WirePanel {}
-      steps:
-      - tool: Welding
-        doAfter: 5
-      
-  - node: highSecurity
-    actions:
-      - !type:ChangeWiresPanelSecurityLevel
-        level: Level4
-    edges:
-    - to: highSecurityBreached
-      conditions:
-      - !type:WirePanel {}
-      steps:
-      - tool: Welding
-        doAfter: 15
-    
-    - to: maxSecurity
-      conditions:
-      - !type:WirePanel {}
-      steps:     
-      - material: MetalRod
-        amount: 2
-        doAfter: 1
-
-## Max security level door: an electric grill is added        
-  - node: maxSecurity
-    actions:
-      - !type:ChangeWiresPanelSecurityLevel
-        level: Level5
-    edges:
-    - to: highSecurity 
-      completed:
-      - !type:AttemptElectrocute
-      - !type:GivePrototype
-        prototype: PartRodMetal1
-        amount: 2
-      conditions:  
-      - !type:WirePanel {}
-      steps:
-      - tool: Cutting
-        doAfter: 0.5 
-
-    - to: superMaxSecurityBreached
-      conditions:
-      - !type:WirePanel {}
-      steps:     
-      - material: Plasteel
-        amount: 2
-        doAfter: 2
-
-## Super max security level door: an additional layer of plasteel is added     
-  - node: superMaxSecurityBreached
-    actions:
-      - !type:ChangeWiresPanelSecurityLevel
-        level: Level6
-    edges:
-    - to: maxSecurity 
-      completed:
-      - !type:GivePrototype
-        prototype: SheetPlasteel1
-        amount: 2
-      conditions:
-      - !type:WirePanel {}
-      steps:
-      - tool: Prying
-        doAfter: 4
-    
-    - to: superMaxSecurity 
-      conditions:  
-      - !type:WirePanel {}
-      steps:
-      - tool: Welding
-        doAfter: 5
-      
-  - node: superMaxSecurity
-    actions:
-      - !type:ChangeWiresPanelSecurityLevel
-        level: Level7
-    edges:
-    - to: superMaxSecurityBreached 
-      conditions:
-      - !type:WirePanel {}
-      steps:
-      - tool: Welding
-        doAfter: 15
index 8910282bb42a631126bdc9f815ccba208ee300bf..07f44a1f8b58ad44ed8a96f2bb302a2964e79650 100644 (file)
@@ -3,6 +3,9 @@
 
 - type: Tag
   id: AirAlarmElectronics
+  
+- type: Tag
+  id: Airlock
 
 - type: Tag
   id: AirSensor
 
 - type: Tag
   id: GeigerCounter
+  
+- type: Tag
+  id: GlassAirlock
 
 - type: Tag
   id: GlassBeaker
 - type: Tag
   id: GuideEmbeded
 
-
 - type: Tag
   id: Hamster
 
 
 - type: Tag
   id: HighRiskItem
+  
+- type: Tag
+  id: HighSecDoor
 
 - type: Tag
   id: Hoe