Use construction graphs for hacking protections (#20265)

This commit is contained in:
chromiumboy
2023-10-05 22:15:03 -05:00
committed by GitHub
parent 8eeedb2427
commit acc9c8940b
20 changed files with 363 additions and 581 deletions

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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()
{
};
}
}
}

View File

@@ -8,6 +8,7 @@ using Content.Shared.Database;
using Robust.Server.Containers; using Robust.Server.Containers;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using System.Linq;
namespace Content.Server.Construction namespace Content.Server.Construction
{ {
@@ -298,9 +299,23 @@ namespace Content.Server.Construction
throw new Exception("Missing construction components"); 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)) if (newEntity == metaData.EntityPrototype?.ID || !_prototypeManager.HasIndex<EntityPrototype>(newEntity))
return null; 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. // Optional resolves.
Resolve(uid, ref containerManager, false); Resolve(uid, ref containerManager, false);

View File

@@ -12,6 +12,7 @@ using Content.Shared.Interaction;
using Content.Shared.Prying.Systems; using Content.Shared.Prying.Systems;
using Content.Shared.Radio.EntitySystems; using Content.Shared.Radio.EntitySystems;
using Content.Shared.Tools.Components; using Content.Shared.Tools.Components;
using Content.Shared.Tools.Systems;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Utility; 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. // Event handling. Add your subscriptions here! Just make sure they're all handled by EnqueueEvent.
SubscribeLocalEvent<ConstructionComponent, InteractUsingEvent>(EnqueueEvent, SubscribeLocalEvent<ConstructionComponent, InteractUsingEvent>(EnqueueEvent,
new []{typeof(AnchorableSystem), typeof(PryingSystem) }, new []{typeof(AnchorableSystem), typeof(PryingSystem), typeof(WeldableSystem)},
new []{typeof(EncryptionKeySystem)}); new []{typeof(EncryptionKeySystem)});
SubscribeLocalEvent<ConstructionComponent, OnTemperatureChangeEvent>(EnqueueEvent); SubscribeLocalEvent<ConstructionComponent, OnTemperatureChangeEvent>(EnqueueEvent);
SubscribeLocalEvent<ConstructionComponent, PartAssemblyPartInsertedEvent>(EnqueueEvent); SubscribeLocalEvent<ConstructionComponent, PartAssemblyPartInsertedEvent>(EnqueueEvent);

View File

@@ -18,7 +18,6 @@ public sealed class AirlockSystem : SharedAirlockSystem
[Dependency] private readonly WiresSystem _wiresSystem = default!; [Dependency] private readonly WiresSystem _wiresSystem = default!;
[Dependency] private readonly PowerReceiverSystem _power = default!; [Dependency] private readonly PowerReceiverSystem _power = default!;
[Dependency] private readonly DoorBoltSystem _bolts = default!; [Dependency] private readonly DoorBoltSystem _bolts = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -153,8 +152,8 @@ public sealed class AirlockSystem : SharedAirlockSystem
{ {
if (TryComp<WiresPanelComponent>(uid, out var panel) && if (TryComp<WiresPanelComponent>(uid, out var panel) &&
panel.Open && panel.Open &&
_prototypeManager.TryIndex<WiresPanelSecurityLevelPrototype>(panel.CurrentSecurityLevelID, out var securityLevelPrototype) && TryComp<WiresPanelSecurityComponent>(uid, out var wiresPanelSecurity) &&
securityLevelPrototype.WiresAccessible && wiresPanelSecurity.WiresAccessible &&
TryComp<ActorComponent>(args.User, out var actor)) TryComp<ActorComponent>(args.User, out var actor))
{ {
_wiresSystem.OpenUserInterface(uid, actor.PlayerSession); _wiresSystem.OpenUserInterface(uid, actor.PlayerSession);

View File

@@ -2,6 +2,8 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using Content.Server.Administration.Logs; using Content.Server.Administration.Logs;
using Content.Server.Construction;
using Content.Server.Construction.Components;
using Content.Server.Power.Components; using Content.Server.Power.Components;
using Content.Server.UserInterface; using Content.Server.UserInterface;
using Content.Shared.Database; using Content.Shared.Database;
@@ -33,6 +35,7 @@ public sealed class WiresSystem : SharedWiresSystem
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!; [Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ConstructionSystem _construction = default!;
// This is where all the wire layouts are stored. // This is where all the wire layouts are stored.
[ViewVariables] private readonly Dictionary<string, WireLayout> _layouts = new(); [ViewVariables] private readonly Dictionary<string, WireLayout> _layouts = new();
@@ -58,6 +61,7 @@ public sealed class WiresSystem : SharedWiresSystem
SubscribeLocalEvent<WiresComponent, WireDoAfterEvent>(OnDoAfter); SubscribeLocalEvent<WiresComponent, WireDoAfterEvent>(OnDoAfter);
SubscribeLocalEvent<ActivatableUIRequiresPanelComponent, ActivatableUIOpenAttemptEvent>(OnAttemptOpenActivatableUI); SubscribeLocalEvent<ActivatableUIRequiresPanelComponent, ActivatableUIOpenAttemptEvent>(OnAttemptOpenActivatableUI);
SubscribeLocalEvent<ActivatableUIRequiresPanelComponent, PanelChangedEvent>(OnActivatableUIPanelChanged); SubscribeLocalEvent<ActivatableUIRequiresPanelComponent, PanelChangedEvent>(OnActivatableUIPanelChanged);
SubscribeLocalEvent<WiresPanelSecurityComponent, WiresPanelSecurityEvent>(SetWiresPanelSecurity);
} }
private void SetOrCreateWireLayout(EntityUid uid, WiresComponent? wires = null) private void SetOrCreateWireLayout(EntityUid uid, WiresComponent? wires = null)
{ {
@@ -459,8 +463,8 @@ public sealed class WiresSystem : SharedWiresSystem
return; return;
if (panel.Open && if (panel.Open &&
_protoMan.TryIndex<WiresPanelSecurityLevelPrototype>(panel.CurrentSecurityLevelID, out var securityLevelPrototype) && TryComp<WiresPanelSecurityComponent>(uid, out var wiresPanelSecurity) &&
securityLevelPrototype.WiresAccessible && wiresPanelSecurity.WiresAccessible &&
(_toolSystem.HasQuality(args.Used, "Cutting", tool) || (_toolSystem.HasQuality(args.Used, "Cutting", tool) ||
_toolSystem.HasQuality(args.Used, "Pulsing", tool))) _toolSystem.HasQuality(args.Used, "Pulsing", tool)))
{ {
@@ -526,6 +530,14 @@ public sealed class WiresSystem : SharedWiresSystem
if (component.WireSeed == 0) if (component.WireSeed == 0)
component.WireSeed = _random.Next(1, int.MaxValue); 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); UpdateUserInterface(uid);
} }
#endregion #endregion
@@ -656,13 +668,14 @@ public sealed class WiresSystem : SharedWiresSystem
RaiseLocalEvent(uid, ref ev); 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); Dirty(uid, component);
if (_protoMan.TryIndex<WiresPanelSecurityLevelPrototype>(component.CurrentSecurityLevelID, out var securityLevelPrototype) && if (!args.WiresAccessible)
securityLevelPrototype.WiresAccessible)
{ {
_uiSystem.TryCloseAll(uid, WiresUiKey.Key); _uiSystem.TryCloseAll(uid, WiresUiKey.Key);
} }

View File

@@ -1,4 +1,4 @@
using Content.Shared.Construction.Steps; using Content.Shared.Construction.Steps;
namespace Content.Shared.Construction namespace Content.Shared.Construction
{ {

View File

@@ -1,4 +1,4 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Content.Shared.Construction.NodeEntities; using Content.Shared.Construction.NodeEntities;
using Content.Shared.Construction.Serialization; using Content.Shared.Construction.Serialization;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
@@ -31,6 +31,20 @@ namespace Content.Shared.Construction
[DataField("entity", customTypeSerializer: typeof(GraphNodeEntitySerializer), serverOnly:true)] [DataField("entity", customTypeSerializer: typeof(GraphNodeEntitySerializer), serverOnly:true)]
public IGraphNodeEntity Entity { get; private set; } = new NullNodeEntity(); 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) public ConstructionGraphEdge? GetEdge(string target)
{ {
foreach (var edge in _edges) foreach (var edge in _edges)

View File

@@ -6,14 +6,11 @@ namespace Content.Shared.Wires;
public abstract class SharedWiresSystem : EntitySystem public abstract class SharedWiresSystem : EntitySystem
{ {
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
SubscribeLocalEvent<WiresPanelComponent, ExaminedEvent>(OnExamine); SubscribeLocalEvent<WiresPanelComponent, ExaminedEvent>(OnExamine);
SubscribeLocalEvent<WiresPanelComponent, WeldableAttemptEvent>(OnWeldableAttempt);
} }
private void OnExamine(EntityUid uid, WiresPanelComponent component, ExaminedEvent args) 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")); args.PushMarkup(Loc.GetString("wires-panel-component-on-examine-open"));
if (_prototypeManager.TryIndex<WiresPanelSecurityLevelPrototype>(component.CurrentSecurityLevelID, out var securityLevelPrototype) && if (TryComp<WiresPanelSecurityComponent>(uid, out var wiresPanelSecurity) &&
securityLevelPrototype.Examine != null) 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();
}
}
} }

View File

@@ -27,14 +27,6 @@ public sealed partial class WiresPanelComponent : Component
[DataField("screwdriverCloseSound")] [DataField("screwdriverCloseSound")]
public SoundSpecifier ScrewdriverCloseSound = new SoundPathSpecifier("/Audio/Machines/screwdriverclose.ogg"); 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> /// <summary>

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -69,10 +69,8 @@
components: components:
- type: Sprite - type: Sprite
sprite: Structures/Doors/Airlocks/Standard/command.rsi sprite: Structures/Doors/Airlocks/Standard/command.rsi
- type: WiresPanel - type: WiresPanelSecurity
securityLevel: Level2 securityLevel: medSecurity
- type: Construction
node: airlockMedSecurity
- type: entity - type: entity
parent: Airlock parent: Airlock
@@ -138,7 +136,10 @@
group: Glass group: Glass
- type: RadiationBlocker - type: RadiationBlocker
resistance: 2 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 - type: entity
parent: AirlockGlass parent: AirlockGlass
id: AirlockEngineeringGlass id: AirlockEngineeringGlass
@@ -218,10 +219,8 @@
sprite: Structures/Doors/Airlocks/Glass/command.rsi sprite: Structures/Doors/Airlocks/Glass/command.rsi
- type: PaintableAirlock - type: PaintableAirlock
group: Glass group: Glass
- type: WiresPanel - type: WiresPanelSecurity
securityLevel: Level2 securityLevel: medSecurity
- type: Construction
node: glassAirlockMedSecurity
- type: entity - type: entity
parent: AirlockGlass parent: AirlockGlass

View File

@@ -74,6 +74,7 @@
enabled: false enabled: false
usesApcPower: true usesApcPower: true
- type: WiresPanel - type: WiresPanel
- type: WiresPanelSecurity
- type: Wires - type: Wires
BoardName: wires-board-name-airlock BoardName: wires-board-name-airlock
LayoutId: Airlock LayoutId: Airlock
@@ -131,5 +132,10 @@
- type: AccessReader - type: AccessReader
- type: StaticPrice - type: StaticPrice
price: 150 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: placement:
mode: SnapgridCenter mode: SnapgridCenter

View File

@@ -67,7 +67,8 @@
enabled: false enabled: false
usesApcPower: true usesApcPower: true
- type: WiresPanel - type: WiresPanel
securityLevel: Level5 - type: WiresPanelSecurity
securityLevel: maxSecurity
- type: Wires - type: Wires
BoardName: wires-board-name-highsec BoardName: wires-board-name-highsec
LayoutId: HighSec LayoutId: HighSec
@@ -94,5 +95,9 @@
key: walls key: walls
mode: NoSprite mode: NoSprite
- type: Construction - type: Construction
graph: HighSecDoor graph: Airlock
node: maxSecurity node: highSecDoor
- type: Tag
tags:
- HighSecDoor
# This tag is used to nagivate the Airlock construction graph. It's needed because this construction graph is shared between Airlock, AirlockGlass, and HighSecDoor

View File

@@ -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

View File

@@ -110,11 +110,14 @@
- tool: Prying - tool: Prying
doAfter: 5 doAfter: 5
## Glass airlock
- node: glassAirlock - node: glassAirlock
entity: AirlockGlass entity: AirlockGlass
doNotReplaceInheritingEntities: true
actions: actions:
- !type:ChangeWiresPanelSecurityLevel - !type:SetWiresPanelSecurity
level: Level0 wiresAccessible: true
weldingAllowed: true
edges: edges:
- to: glassElectronics - to: glassElectronics
conditions: conditions:
@@ -132,7 +135,7 @@
- tool: Prying - tool: Prying
doAfter: 2 doAfter: 2
- to: glassAirlockMedSecurityBreached - to: medSecurityUnfinished
conditions: conditions:
- !type:WirePanel {} - !type:WirePanel {}
steps: steps:
@@ -140,235 +143,22 @@
amount: 2 amount: 2
doAfter: 2 doAfter: 2
- to: glassAirlockHighSecurityBreached - to: highSecurityUnfinished
conditions: conditions:
- !type:WirePanel {} - !type:WirePanel {}
steps: steps:
- material: Plasteel - material: Plasteel
amount: 2 amount: 2
doAfter: 2 doAfter: 2
## Return node so that removing all internal plating doesn't reset the door
- node: glassAirlockUnsecured
actions:
- !type:ChangeWiresPanelSecurityLevel
level: Level0
edges:
- to: glassElectronics
conditions:
- !type:EntityAnchored {}
- !type:DoorWelded {}
- !type:DoorBolted
value: false
- !type:WirePanel {}
- !type:AllWiresCut
completed:
- !type:SpawnPrototype
prototype: SheetRGlass1
amount: 1
steps:
- tool: Prying
doAfter: 2
- to: glassAirlockMedSecurityBreached
conditions:
- !type:WirePanel {}
steps:
- material: Steel
amount: 2
doAfter: 2
- to: glassAirlockHighSecurityBreached ## Standard airlock
conditions:
- !type:WirePanel {}
steps:
- material: Plasteel
amount: 2
doAfter: 2
## Medium security level airlock: a layer of steel plating protects the internal wiring
- node: glassAirlockMedSecurityBreached
actions:
- !type:ChangeWiresPanelSecurityLevel
level: Level1
edges:
- to: glassAirlockUnsecured
completed:
- !type:GivePrototype
prototype: SheetSteel1
amount: 2
conditions:
- !type:WirePanel {}
steps:
- tool: Prying
doAfter: 4
- to: glassAirlockMedSecurity
conditions:
- !type:WirePanel {}
steps:
- tool: Welding
doAfter: 3
- node: glassAirlockMedSecurity
actions:
- !type:ChangeWiresPanelSecurityLevel
level: Level2
edges:
- to: glassAirlockMedSecurityBreached
conditions:
- !type:WirePanel {}
steps:
- tool: Welding
doAfter: 10
## High security level airlock: a layer of plasteel plating protects the internal wiring
- node: glassAirlockHighSecurityBreached
actions:
- !type:ChangeWiresPanelSecurityLevel
level: Level3
edges:
- to: glassAirlockUnsecured
completed:
- !type:GivePrototype
prototype: SheetPlasteel1
amount: 2
conditions:
- !type:WirePanel {}
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
completed:
- !type:AttemptElectrocute
- !type:GivePrototype
prototype: PartRodMetal1
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
completed:
- !type:GivePrototype
prototype: SheetPlasteel1
amount: 2
conditions:
- !type:WirePanel {}
steps:
- tool: Prying
doAfter: 4
- to: glassAirlockSuperMaxSecurity
conditions:
- !type:WirePanel {}
steps:
- tool: Welding
doAfter: 5
- node: glassAirlockSuperMaxSecurity
actions:
- !type:ChangeWiresPanelSecurityLevel
level: Level7
edges:
- to: glassAirlockSuperMaxSecurityBreached
conditions:
- !type:WirePanel {}
steps:
- tool: Welding
doAfter: 15
- node: airlock - node: airlock
entity: Airlock entity: Airlock
doNotReplaceInheritingEntities: true
actions: actions:
- !type:ChangeWiresPanelSecurityLevel - !type:SetWiresPanelSecurity
level: Level0 wiresAccessible: true
edges: weldingAllowed: true
- 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: edges:
- to: wired - to: wired
conditions: conditions:
@@ -384,15 +174,15 @@
- tool: Prying - tool: Prying
doAfter: 5 doAfter: 5
- to: airlockMedSecurityBreached - to: medSecurityUnfinished
conditions: conditions:
- !type:WirePanel {} - !type:WirePanel {}
steps: steps:
- material: Steel - material: Steel
amount: 2 amount: 2
doAfter: 2 doAfter: 2
- to: airlockHighSecurityBreached - to: highSecurityUnfinished
conditions: conditions:
- !type:WirePanel {} - !type:WirePanel {}
steps: steps:
@@ -400,79 +190,166 @@
amount: 2 amount: 2
doAfter: 2 doAfter: 2
## Medium security level airlock: a layer of steel plating protects the internal wiring ## High security door
- node: airlockMedSecurityBreached - node: highSecDoor
actions: actions:
- !type:ChangeWiresPanelSecurityLevel - !type:SetWiresPanelSecurity
level: Level1 wiresAccessible: true
weldingAllowed: true
edges:
- to: medSecurityUnfinished
conditions:
- !type:WirePanel {}
steps:
- material: Steel
amount: 2
doAfter: 2
- to: highSecurityUnfinished
conditions:
- !type:WirePanel {}
steps:
- material: Plasteel
amount: 2
doAfter: 2
## Medium security level door: a layer of steel plating protects the internal wiring
- node: medSecurityUnfinished
actions:
- !type:SetWiresPanelSecurity
examine: wires-panel-component-on-examine-security-level1
wiresAccessible: false
weldingAllowed: false
edges: edges:
- to: airlockUnsecured - to: glassAirlock
completed: completed:
- !type:GivePrototype - !type:GivePrototype
prototype: SheetSteel1 prototype: SheetSteel1
amount: 2 amount: 2
conditions: conditions:
- !type:WirePanel {} - !type:WirePanel {}
- !type:HasTag
tag: GlassAirlock
steps:
- tool: Prying
doAfter: 4
- to: airlock
completed:
- !type:GivePrototype
prototype: SheetSteel1
amount: 2
conditions:
- !type:WirePanel {}
- !type:HasTag
tag: Airlock
steps:
- tool: Prying
doAfter: 4
- to: highSecDoor
completed:
- !type:GivePrototype
prototype: SheetSteel1
amount: 2
conditions:
- !type:WirePanel {}
- !type:HasTag
tag: HighSecDoor
steps: steps:
- tool: Prying - tool: Prying
doAfter: 4 doAfter: 4
- to: airlockMedSecurity - to: medSecurity
conditions: conditions:
- !type:WirePanel {} - !type:WirePanel {}
steps: steps:
- tool: Welding - tool: Welding
doAfter: 3 doAfter: 3
- node: airlockMedSecurity - node: medSecurity
actions: actions:
- !type:ChangeWiresPanelSecurityLevel - !type:SetWiresPanelSecurity
level: Level2 examine: wires-panel-component-on-examine-security-level2
wiresAccessible: false
weldingAllowed: false
edges: edges:
- to: airlockMedSecurityBreached - to: medSecurityUnfinished
conditions: conditions:
- !type:WirePanel {} - !type:WirePanel {}
steps: steps:
- tool: Welding - tool: Welding
doAfter: 10 doAfter: 10
## High security level airlock: a layer of plasteel plating protects the internal wiring ## High security level door: a layer of plasteel plating protects the internal wiring
- node: airlockHighSecurityBreached - node: highSecurityUnfinished
actions: actions:
- !type:ChangeWiresPanelSecurityLevel - !type:SetWiresPanelSecurity
level: Level3 examine: wires-panel-component-on-examine-security-level3
wiresAccessible: false
weldingAllowed: false
edges: edges:
- to: airlockUnsecured - to: glassAirlock
completed: completed:
- !type:GivePrototype - !type:GivePrototype
prototype: SheetPlasteel1 prototype: SheetPlasteel1
amount: 2 amount: 2
conditions: conditions:
- !type:WirePanel {} - !type:WirePanel {}
- !type:HasTag
tag: GlassAirlock
steps:
- tool: Prying
doAfter: 4
- to: airlock
completed:
- !type:GivePrototype
prototype: SheetPlasteel1
amount: 2
conditions:
- !type:WirePanel {}
- !type:HasTag
tag: Airlock
steps:
- tool: Prying
doAfter: 4
- to: highSecDoor
completed:
- !type:GivePrototype
prototype: SheetPlasteel1
amount: 2
conditions:
- !type:WirePanel {}
- !type:HasTag
tag: HighSecDoor
steps: steps:
- tool: Prying - tool: Prying
doAfter: 4 doAfter: 4
- to: airlockHighSecurity - to: highSecurity
conditions: conditions:
- !type:WirePanel {} - !type:WirePanel {}
steps: steps:
- tool: Welding - tool: Welding
doAfter: 5 doAfter: 5
- node: airlockHighSecurity - node: highSecurity
actions: actions:
- !type:ChangeWiresPanelSecurityLevel - !type:SetWiresPanelSecurity
level: Level4 examine: wires-panel-component-on-examine-security-level4
wiresAccessible: false
weldingAllowed: false
edges: edges:
- to: airlockHighSecurityBreached - to: highSecurityUnfinished
conditions: conditions:
- !type:WirePanel {} - !type:WirePanel {}
steps: steps:
- tool: Welding - tool: Welding
doAfter: 15 doAfter: 15
- to: airlockMaxSecurity - to: maxSecurity
conditions: conditions:
- !type:WirePanel {} - !type:WirePanel {}
steps: steps:
@@ -480,13 +357,15 @@
amount: 2 amount: 2
doAfter: 1 doAfter: 1
## Max security level airlock: an electric grill is added ## Max security level door: an electric grill is added
- node: airlockMaxSecurity - node: maxSecurity
actions: actions:
- !type:ChangeWiresPanelSecurityLevel - !type:SetWiresPanelSecurity
level: Level5 examine: wires-panel-component-on-examine-security-level5
wiresAccessible: false
weldingAllowed: true
edges: edges:
- to: airlockHighSecurity - to: highSecurity
completed: completed:
- !type:AttemptElectrocute - !type:AttemptElectrocute
- !type:GivePrototype - !type:GivePrototype
@@ -498,7 +377,7 @@
- tool: Cutting - tool: Cutting
doAfter: 0.5 doAfter: 0.5
- to: airlockSuperMaxSecurityBreached - to: superMaxSecurityUnfinished
conditions: conditions:
- !type:WirePanel {} - !type:WirePanel {}
steps: steps:
@@ -506,13 +385,15 @@
amount: 2 amount: 2
doAfter: 2 doAfter: 2
## Super max security level airlock: an additional layer of plasteel is added ## Super max security level door: an additional layer of plasteel is added
- node: airlockSuperMaxSecurityBreached - node: superMaxSecurityUnfinished
actions: actions:
- !type:ChangeWiresPanelSecurityLevel - !type:SetWiresPanelSecurity
level: Level6 examine: wires-panel-component-on-examine-security-level6
wiresAccessible: false
weldingAllowed: false
edges: edges:
- to: airlockMaxSecurity - to: maxSecurity
completed: completed:
- !type:GivePrototype - !type:GivePrototype
prototype: SheetPlasteel1 prototype: SheetPlasteel1
@@ -523,21 +404,24 @@
- tool: Prying - tool: Prying
doAfter: 4 doAfter: 4
- to: airlockSuperMaxSecurity - to: superMaxSecurity
conditions: conditions:
- !type:WirePanel {} - !type:WirePanel {}
steps: steps:
- tool: Welding - tool: Welding
doAfter: 5 doAfter: 5
- node: airlockSuperMaxSecurity - node: superMaxSecurity
actions: actions:
- !type:ChangeWiresPanelSecurityLevel - !type:SetWiresPanelSecurity
level: Level7 examine: wires-panel-component-on-examine-security-level7
wiresAccessible: false
weldingAllowed: false
edges: edges:
- to: airlockSuperMaxSecurityBreached - to: superMaxSecurityUnfinished
conditions: conditions:
- !type:WirePanel {} - !type:WirePanel {}
steps: steps:
- tool: Welding - tool: Welding
doAfter: 15 doAfter: 15

View File

@@ -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

View File

@@ -3,6 +3,9 @@
- type: Tag - type: Tag
id: AirAlarmElectronics id: AirAlarmElectronics
- type: Tag
id: Airlock
- type: Tag - type: Tag
id: AirSensor id: AirSensor
@@ -487,6 +490,9 @@
- type: Tag - type: Tag
id: GeigerCounter id: GeigerCounter
- type: Tag
id: GlassAirlock
- type: Tag - type: Tag
id: GlassBeaker id: GlassBeaker
@@ -503,7 +509,6 @@
- type: Tag - type: Tag
id: GuideEmbeded id: GuideEmbeded
- type: Tag - type: Tag
id: Hamster id: Hamster
@@ -554,6 +559,9 @@
- type: Tag - type: Tag
id: HighRiskItem id: HighRiskItem
- type: Tag
id: HighSecDoor
- type: Tag - type: Tag
id: Hoe id: Hoe