diff --git a/Content.Server/Construction/Completions/AttemptElectrocute.cs b/Content.Server/Construction/Completions/AttemptElectrocute.cs index cabb792552fe59..eb6c1007648a28 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 +namespace Content.Server.Construction.Completions; + +[DataDefinition] +public sealed class AttemptElectrocute : IGraphAction { - [DataDefinition] - public sealed class AttemptElectrocute : IGraphAction + public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager) { - public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager) - { - if (userUid == null) - return; + 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); - entityManager.EntitySysManager.GetEntitySystem().TryDoElectrifiedAct(uid, userUid.Value); - } + electrified.Enabled = currentValue; } } diff --git a/Content.Server/Construction/Completions/ChangeWiresPanelSecurityLevel.cs b/Content.Server/Construction/Completions/ChangeWiresPanelSecurityLevel.cs new file mode 100644 index 00000000000000..28d7c833d3f1b9 --- /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 7eb56035d597c2..c8a43ae2e434c4 100644 --- a/Content.Server/Doors/Systems/AirlockSystem.cs +++ b/Content.Server/Doors/Systems/AirlockSystem.cs @@ -10,181 +10,180 @@ 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!; + [Dependency] private readonly WiresSystem _wiresSystem = default!; + [Dependency] private readonly PowerReceiverSystem _power = default!; + [Dependency] private readonly DoorBoltSystem _bolts = default!; - public override void Initialize() - { - base.Initialize(); + public override void Initialize() + { + base.Initialize(); - SubscribeLocalEvent(OnAirlockInit); - SubscribeLocalEvent(OnSignalReceived); + SubscribeLocalEvent(OnAirlockInit); + SubscribeLocalEvent(OnSignalReceived); - SubscribeLocalEvent(OnPowerChanged); - SubscribeLocalEvent(OnStateChanged); - SubscribeLocalEvent(OnBeforeDoorOpened); - SubscribeLocalEvent(OnBeforeDoorDenied); - SubscribeLocalEvent(OnActivate, before: new [] {typeof(DoorSystem)}); - SubscribeLocalEvent(OnGetPryMod); - SubscribeLocalEvent(OnDoorPry); + 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) + private void OnAirlockInit(EntityUid uid, AirlockComponent component, ComponentInit args) + { + if (TryComp(uid, out var receiverComponent)) { - if (TryComp(uid, out var receiverComponent)) - { - Appearance.SetData(uid, DoorVisuals.Powered, receiverComponent.Powered); - Appearance.SetData(uid, DoorVisuals.ClosedLights, true); // Corvax-Resprite-Airlocks - } + Appearance.SetData(uid, DoorVisuals.Powered, receiverComponent.Powered); + Appearance.SetData(uid, DoorVisuals.ClosedLights, true); // Corvax-Resprite-Airlocks } + } - private void OnSignalReceived(EntityUid uid, AirlockComponent component, ref SignalReceivedEvent args) + private void OnSignalReceived(EntityUid uid, AirlockComponent component, ref SignalReceivedEvent args) + { + if (args.Port == component.AutoClosePort) { - if (args.Port == component.AutoClosePort) - { - component.AutoClose = false; - } + component.AutoClose = false; } + } - private void OnPowerChanged(EntityUid uid, AirlockComponent component, ref PowerChangedEvent args) + private void OnPowerChanged(EntityUid uid, AirlockComponent component, ref PowerChangedEvent args) + { + if (TryComp(uid, out var appearanceComponent)) { - if (TryComp(uid, out var appearanceComponent)) - { - Appearance.SetData(uid, DoorVisuals.Powered, args.Powered, appearanceComponent); - } + Appearance.SetData(uid, DoorVisuals.Powered, args.Powered, appearanceComponent); + } - if (!TryComp(uid, out DoorComponent? door)) - return; + 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); - } + if (!args.Powered) + { + // stop any scheduled auto-closing + if (door.State == DoorState.Open) + DoorSystem.SetNextStateChange(uid, null); } - - private void OnStateChanged(EntityUid uid, AirlockComponent component, DoorStateChangedEvent args) + else { - // 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; + 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. - /// - /// Updates the auto close timer. - /// - public void UpdateAutoClose(EntityUid uid, AirlockComponent? airlock = null, DoorComponent? door = null) + // Only show the maintenance panel if the airlock is closed + if (TryComp(uid, out var wiresPanel)) { - if (!Resolve(uid, ref airlock, ref door)) - return; + _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); - if (door.State != DoorState.Open) - return; + // Make sure the airlock auto closes again next time it is opened + if (args.State == DoorState.Closed) + component.AutoClose = true; + } - if (!airlock.AutoClose) - return; + /// + /// 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 (!CanChangeState(uid, airlock)) - return; + if (door.State != DoorState.Open) + return; - var autoev = new BeforeDoorAutoCloseEvent(); - RaiseLocalEvent(uid, autoev, false); - if (autoev.Cancelled) - return; + if (!airlock.AutoClose) + return; - DoorSystem.SetNextStateChange(uid, airlock.AutoCloseDelay * airlock.AutoCloseDelayModifier); - } + if (!CanChangeState(uid, airlock)) + return; - private void OnBeforeDoorOpened(EntityUid uid, AirlockComponent component, BeforeDoorOpenedEvent args) - { - if (!CanChangeState(uid, component)) - args.Cancel(); - } + var autoev = new BeforeDoorAutoCloseEvent(); + RaiseLocalEvent(uid, autoev, false); + if (autoev.Cancelled) + return; - protected override void OnBeforeDoorClosed(EntityUid uid, AirlockComponent component, BeforeDoorClosedEvent args) - { - base.OnBeforeDoorClosed(uid, component, args); + DoorSystem.SetNextStateChange(uid, airlock.AutoCloseDelay * airlock.AutoCloseDelayModifier); + } - if (args.Cancelled) - return; + private void OnBeforeDoorOpened(EntityUid uid, AirlockComponent component, BeforeDoorOpenedEvent args) + { + if (!CanChangeState(uid, component)) + args.Cancel(); + } - // 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. + protected override void OnBeforeDoorClosed(EntityUid uid, AirlockComponent component, BeforeDoorClosedEvent args) + { + base.OnBeforeDoorClosed(uid, component, args); - if (TryComp(uid, out DoorComponent? door) - && !door.Partial - && !CanChangeState(uid, component)) - { - args.Cancel(); - } - } + if (args.Cancelled) + return; - private void OnBeforeDoorDenied(EntityUid uid, AirlockComponent component, BeforeDoorDeniedEvent args) - { - if (!CanChangeState(uid, component)) - args.Cancel(); - } + // 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. - private void OnActivate(EntityUid uid, AirlockComponent component, ActivateInWorldEvent args) + if (TryComp(uid, out DoorComponent? door) + && !door.Partial + && !CanChangeState(uid, component)) { - 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; - } + args.Cancel(); } + } - private void OnGetPryMod(EntityUid uid, AirlockComponent component, DoorGetPryTimeModifierEvent args) + 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)) { - if (_power.IsPowered(uid)) - args.PryTimeModifier *= component.PoweredPryModifier; + _wiresSystem.OpenUserInterface(uid, actor.PlayerSession); + args.Handled = true; + return; } - private void OnDoorPry(EntityUid uid, AirlockComponent component, BeforeDoorPryEvent args) + if (component.KeepOpenIfClicked) { - 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(); - } + // Disable auto close + component.AutoClose = false; } + } - public bool CanChangeState(EntityUid uid, AirlockComponent component) + 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)) { - return this.IsPowered(uid, EntityManager) && !_bolts.IsBolted(uid); + 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 70f7adfd289393..898addd0ffaef9 100644 --- a/Content.Server/Electrocution/ElectrocutionSystem.cs +++ b/Content.Server/Electrocution/ElectrocutionSystem.cs @@ -22,7 +22,6 @@ 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 daaa44836cea32..e42f1f9104ef8a 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.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 @@ private void OnExamine(EntityUid uid, WeldableComponent component, ExaminedEvent 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 8c99852971338d..26b85e724ba4ed 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 @@ private void OnInteractUsing(EntityUid uid, WiresComponent component, InteractUs 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 void TogglePanel(EntityUid uid, WiresPanelComponent component, bool open) 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 d7ddac4de2d5e4..78cb2980708268 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 override void Initialize() { 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 668e7f01007e93..683bd3f830966b 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 00000000000000..1fcc982f109f14 --- /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/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 8871e0b2a30075..2d6d4cb7a2585c 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,22 +1,4 @@ Entries: -- author: Slava0135 - changes: - - {message: added mass hallucinations event that temporarily makes everyone on station - hear random sounds (paracusia), type: Add} - id: 4006 - time: '2023-06-15T06:45:51.0000000+00:00' -- author: EmoGarbage404 - changes: - - {message: Our top scientists have injected our artifacts with foaming agents to - greatly increase their foam output. Let's just hope that there's nothing dangerous - inside of it., type: Fix} - id: 4007 - time: '2023-06-15T11:26:10.0000000+00:00' -- author: lzk - changes: - - {message: Changed sprites, type: Tweak} - id: 4008 - time: '2023-06-15T11:55:07.0000000+00:00' - author: deltanedas changes: - {message: Fixed being able to insert tanks/jetpacks into locked gas canisters., @@ -2979,3 +2961,24 @@ Entries: - {message: Advanced laser guns recharge 25% slower than before., type: Tweak} id: 4505 time: '2023-08-10T07:27:02.0000000+00:00' +- author: chromiumboy + changes: + - {message: Obstacles to deter hackers can now be added to airlocks., type: Add} + - {message: Security and Atmospherics airlocks start with a moderate level of protection. + Command airlocks start with an even higher level of security., type: Add} + id: 4506 + time: '2023-08-10T08:33:04.0000000+00:00' +- author: EmoGarbage404 + changes: + - {message: The Syndicate are no longer interested in stealing Cargo's request computer + boards., type: Remove} + id: 4507 + time: '2023-08-10T08:34:38.0000000+00:00' +- author: Equivocateur + changes: + - {message: 'Added an electrical disruption kit to syndicate operatives, containing + 3 EMP grenades and an EMP implanter. Costs 6 telecrystals.', type: Add} + - {message: Changed EMP grenade pricing to 2 telecrystals., type: Tweak} + - {message: Changed EMP implant pricing to 3 telecrystals., type: Tweak} + id: 4508 + time: '2023-08-10T08:40:17.0000000+00:00' diff --git a/Resources/Locale/en-US/store/uplink-catalog.ftl b/Resources/Locale/en-US/store/uplink-catalog.ftl index dfed0cff9e5be7..f91dc88fe231f7 100644 --- a/Resources/Locale/en-US/store/uplink-catalog.ftl +++ b/Resources/Locale/en-US/store/uplink-catalog.ftl @@ -140,6 +140,9 @@ uplink-deathrattle-implant-name = Box Of Deathrattle Implants uplink-deathrattle-implant-desc = A box containing enough deathrattle implants for the whole squad. Relays a message containing your position to the syndicate channel when you go into a critical state or die. # Bundles +uplink-emp-kit-name = Electrical Disruptor Kit +uplink-emp-kit-desc = The ultimate reversal on energy-based weaponry: Disables disablers, stuns stunbatons, discharges laser guns! Contains 3 EMP grenades and an EMP implanter. Note: Does not disrupt actual firearms. + uplink-meds-bundle-name = Medical Bundle uplink-meds-bundle-desc = All you need to get your comrades back in the fight: mainly a combat medkit, a defibrillator and three combat medipens. 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 00000000000000..a932877c582a41 --- /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/Catalog/Fills/Boxes/syndicate.yml b/Resources/Prototypes/Catalog/Fills/Boxes/syndicate.yml new file mode 100644 index 00000000000000..a6c3ca0d6aaab5 --- /dev/null +++ b/Resources/Prototypes/Catalog/Fills/Boxes/syndicate.yml @@ -0,0 +1,12 @@ +- type: entity + id: ElectricalDisruptionKit + parent: BoxCardboard + name: electrical disruption kit + suffix: Filled + components: + - type: StorageFill + contents: + - id: EmpGrenade + amount: 3 + - id: EmpImplanter + amount: 1 diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index d85206c212e096..ae8ac9c44bcf0f 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -204,7 +204,7 @@ description: uplink-emp-grenade-desc productEntity: EmpGrenade cost: - Telecrystal: 3 + Telecrystal: 2 categories: - UplinkExplosives @@ -526,7 +526,7 @@ icon: { sprite: /Textures/Objects/Magic/magicactions.rsi, state: shield } productEntity: EmpImplanter cost: - Telecrystal: 5 + Telecrystal: 3 categories: - UplinkImplants @@ -587,6 +587,16 @@ # Bundles +- type: listing + id: UplinkEmpKit + name: uplink-emp-kit-name + description: uplink-emp-kit-desc + productEntity: ElectricalDisruptionKit + cost: + Telecrystal: 6 + categories: + - UplinkBundles + - type: listing id: UplinkAmmoBundle name: uplink-ammo-bundle-name diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml index 44ea3cf1f02e89..1066bbb07ce9fb 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml @@ -87,7 +87,6 @@ - type: Tag tags: - DroneUsable - - HighRiskItem - type: entity id: CargoBountyComputerCircuitboard @@ -377,4 +376,4 @@ - type: StaticPrice price: 150 - type: ComputerBoard - prototype: ComputerMassMedia \ No newline at end of file + prototype: ComputerMassMedia diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/airlocks.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/airlocks.yml index cdd0ac6a90c54a..0d90cd1e451d7e 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 00000000000000..fb5b7626620643 --- /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/Objectives/objectiveGroups.yml b/Resources/Prototypes/Objectives/objectiveGroups.yml index f307749587047d..b834e4f0c3d211 100644 --- a/Resources/Prototypes/Objectives/objectiveGroups.yml +++ b/Resources/Prototypes/Objectives/objectiveGroups.yml @@ -16,7 +16,6 @@ NukeDiskStealObjective: 1 IDComputerBoardStealObjective: 1 MagbootsStealObjective: 1 - SupplyConsoleBoardStealObjective: 1 CorgiMeatStealObjective: 1 CaptainGunStealObjective: 0.5 CaptainJetpackStealObjective: 0.5 diff --git a/Resources/Prototypes/Objectives/traitorObjectives.yml b/Resources/Prototypes/Objectives/traitorObjectives.yml index b66abb398fa16b..d4bd660157b004 100644 --- a/Resources/Prototypes/Objectives/traitorObjectives.yml +++ b/Resources/Prototypes/Objectives/traitorObjectives.yml @@ -187,21 +187,6 @@ prototype: ClothingShoesBootsMagAdv owner: job-name-ce -- type: objective - id: SupplyConsoleBoardStealObjective - issuer: syndicate - requirements: - - !type:TraitorRequirement {} - - !type:IncompatibleConditionsRequirement - conditions: - - DieCondition - - !type:NotRoleRequirement - roleId: Quartermaster - conditions: - - !type:StealCondition - prototype: CargoRequestComputerCircuitboard - owner: job-name-qm - - type: objective id: CorgiMeatStealObjective issuer: syndicate diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/structures/airlock.yml b/Resources/Prototypes/Recipes/Construction/Graphs/structures/airlock.yml index 2faa18563a4a17..47478ac0fe835b 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 diff --git a/Resources/Prototypes/SS220/Entities/Objects/Weapons/Melee/telescopichka.yml b/Resources/Prototypes/SS220/Entities/Objects/Weapons/Melee/telescopichka.yml index 7ce5f7deea8a2c..dbcf754086aa48 100644 --- a/Resources/Prototypes/SS220/Entities/Objects/Weapons/Melee/telescopichka.yml +++ b/Resources/Prototypes/SS220/Entities/Objects/Weapons/Melee/telescopichka.yml @@ -14,8 +14,6 @@ - type: SwitchableWeapon openSound: "/Audio/SS220/Weapons/telescopichka/batonextend.ogg" closeSound: "/Audio/SS220/Weapons/telescopichka/batonextend.ogg" - bonkSound: !type:SoundCollectionSpecifier - collection: BatonHit damageOpen: types: Blunt: 1