From 1a6bd6f3f14ef1446801c90a3b78c84ab0398eb2 Mon Sep 17 00:00:00 2001 From: Fildrance Date: Fri, 27 Sep 2024 10:22:17 +0300 Subject: [PATCH 1/8] Fixup playerspawn stuff (#31546) * Fixup playerspawn stuff - Also removed arrivals forcing, this should just turn containerspawnpoint off. * fix this one * test fix * really fix --- .../StationAi/StationAiSystem.Airlock.cs | 67 +++++++-- .../Systems/AdminVerbSystem.Tools.cs | 10 +- .../Completions/AttemptElectrocute.cs | 1 + .../Doors/WireActions/DoorBoltWireAction.cs | 1 - .../Components/ElectrifiedComponent.cs | 91 ------------ .../Electrocution/ElectrocutionSystem.cs | 11 ++ Content.Server/Power/PowerWireAction.cs | 2 + Content.Server/Remotes/DoorRemoteSystem.cs | 2 +- .../Doors/Components/AirlockComponent.cs | 13 ++ .../Doors/Systems/SharedAirlockSystem.cs | 22 ++- .../Doors/Systems/SharedDoorSystem.Bolts.cs | 15 +- .../Doors/Systems/SharedDoorSystem.cs | 4 + .../Components/ElectrifiedComponent.cs | 131 ++++++++++++++++++ .../SharedElectrocutionSystem.cs | 14 ++ .../SharedPowerReceiverSystem.cs | 4 +- .../SharedStationAiSystem.Airlock.cs | 71 +++++++++- .../StationAi/SharedStationAiSystem.Held.cs | 65 +++++++-- .../StationAi/SharedStationAiSystem.cs | 41 +++--- .../Audio/Machines/airlock_electrify_off.ogg | Bin 0 -> 9989 bytes .../Audio/Machines/airlock_electrify_on.ogg | Bin 0 -> 10481 bytes .../Audio/Machines/airlock_emergencyoff.ogg | Bin 0 -> 7952 bytes .../Audio/Machines/airlock_emergencyon.ogg | Bin 0 -> 10094 bytes Resources/Audio/Machines/attributions.yml | 14 ++ .../Locale/en-US/silicons/station-ai.ftl | 8 ++ .../Actions/actions_ai.rsi/bolt_door.png | Bin 0 -> 372 bytes .../actions_ai.rsi/door_overcharge_off.png | Bin 0 -> 614 bytes .../actions_ai.rsi/door_overcharge_on.png | Bin 0 -> 495 bytes .../Actions/actions_ai.rsi/emergency_off.png | Bin 0 -> 876 bytes .../Actions/actions_ai.rsi/emergency_on.png | Bin 0 -> 767 bytes .../Actions/actions_ai.rsi/meta.json | 78 +++++++---- .../Actions/actions_ai.rsi/unbolt_door.png | Bin 0 -> 588 bytes 31 files changed, 497 insertions(+), 168 deletions(-) delete mode 100644 Content.Server/Electrocution/Components/ElectrifiedComponent.cs create mode 100644 Content.Shared/Electrocution/Components/ElectrifiedComponent.cs create mode 100644 Resources/Audio/Machines/airlock_electrify_off.ogg create mode 100644 Resources/Audio/Machines/airlock_electrify_on.ogg create mode 100644 Resources/Audio/Machines/airlock_emergencyoff.ogg create mode 100644 Resources/Audio/Machines/airlock_emergencyon.ogg create mode 100644 Resources/Textures/Interface/Actions/actions_ai.rsi/bolt_door.png create mode 100644 Resources/Textures/Interface/Actions/actions_ai.rsi/door_overcharge_off.png create mode 100644 Resources/Textures/Interface/Actions/actions_ai.rsi/door_overcharge_on.png create mode 100644 Resources/Textures/Interface/Actions/actions_ai.rsi/emergency_off.png create mode 100644 Resources/Textures/Interface/Actions/actions_ai.rsi/emergency_on.png create mode 100644 Resources/Textures/Interface/Actions/actions_ai.rsi/unbolt_door.png diff --git a/Content.Client/Silicons/StationAi/StationAiSystem.Airlock.cs b/Content.Client/Silicons/StationAi/StationAiSystem.Airlock.cs index bf6b65a969..d5bc764b34 100644 --- a/Content.Client/Silicons/StationAi/StationAiSystem.Airlock.cs +++ b/Content.Client/Silicons/StationAi/StationAiSystem.Airlock.cs @@ -1,4 +1,5 @@ using Content.Shared.Doors.Components; +using Content.Shared.Electrocution; using Content.Shared.Silicons.StationAi; using Robust.Shared.Utility; @@ -6,25 +7,69 @@ namespace Content.Client.Silicons.StationAi; public sealed partial class StationAiSystem { + private readonly ResPath _aiActionsRsi = new ResPath("/Textures/Interface/Actions/actions_ai.rsi"); + private void InitializeAirlock() { SubscribeLocalEvent(OnDoorBoltGetRadial); + SubscribeLocalEvent(OnEmergencyAccessGetRadial); + SubscribeLocalEvent(OnDoorElectrifiedGetRadial); } private void OnDoorBoltGetRadial(Entity ent, ref GetStationAiRadialEvent args) { - args.Actions.Add(new StationAiRadial() - { - Sprite = ent.Comp.BoltsDown ? - new SpriteSpecifier.Rsi( - new ResPath("/Textures/Structures/Doors/Airlocks/Standard/basic.rsi"), "open") : - new SpriteSpecifier.Rsi( - new ResPath("/Textures/Structures/Doors/Airlocks/Standard/basic.rsi"), "closed"), - Tooltip = ent.Comp.BoltsDown ? Loc.GetString("bolt-open") : Loc.GetString("bolt-close"), - Event = new StationAiBoltEvent() + args.Actions.Add( + new StationAiRadial + { + Sprite = ent.Comp.BoltsDown + ? new SpriteSpecifier.Rsi(_aiActionsRsi, "unbolt_door") + : new SpriteSpecifier.Rsi(_aiActionsRsi, "bolt_door"), + Tooltip = ent.Comp.BoltsDown + ? Loc.GetString("bolt-open") + : Loc.GetString("bolt-close"), + Event = new StationAiBoltEvent + { + Bolted = !ent.Comp.BoltsDown, + } + } + ); + } + + private void OnEmergencyAccessGetRadial(Entity ent, ref GetStationAiRadialEvent args) + { + args.Actions.Add( + new StationAiRadial + { + Sprite = ent.Comp.EmergencyAccess + ? new SpriteSpecifier.Rsi(_aiActionsRsi, "emergency_off") + : new SpriteSpecifier.Rsi(_aiActionsRsi, "emergency_on"), + Tooltip = ent.Comp.EmergencyAccess + ? Loc.GetString("emergency-access-off") + : Loc.GetString("emergency-access-on"), + Event = new StationAiEmergencyAccessEvent + { + EmergencyAccess = !ent.Comp.EmergencyAccess, + } + } + ); + } + + private void OnDoorElectrifiedGetRadial(Entity ent, ref GetStationAiRadialEvent args) + { + args.Actions.Add( + new StationAiRadial { - Bolted = !ent.Comp.BoltsDown, + Sprite = ent.Comp.Enabled + ? new SpriteSpecifier.Rsi(_aiActionsRsi, "door_overcharge_off") + : new SpriteSpecifier.Rsi(_aiActionsRsi, "door_overcharge_on"), + Tooltip = ent.Comp.Enabled + ? Loc.GetString("electrify-door-off") + : Loc.GetString("electrify-door-on"), + Event = new StationAiElectrifiedEvent + { + Electrified = !ent.Comp.Enabled, + } } - }); + ); } } diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs index 3aa1c20cb0..de4f7910c7 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs @@ -90,22 +90,22 @@ private void AddTricksVerbs(GetVerbsEvent args) args.Verbs.Add(bolt); } - if (TryComp(args.Target, out var airlock)) + if (TryComp(args.Target, out var airlockComp)) { Verb emergencyAccess = new() { - Text = airlock.EmergencyAccess ? "Emergency Access Off" : "Emergency Access On", + Text = airlockComp.EmergencyAccess ? "Emergency Access Off" : "Emergency Access On", Category = VerbCategory.Tricks, Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/emergency_access.png")), Act = () => { - _airlockSystem.ToggleEmergencyAccess(args.Target, airlock); + _airlockSystem.SetEmergencyAccess((args.Target, airlockComp), !airlockComp.EmergencyAccess); }, Impact = LogImpact.Medium, - Message = Loc.GetString(airlock.EmergencyAccess + Message = Loc.GetString(airlockComp.EmergencyAccess ? "admin-trick-emergency-access-off-description" : "admin-trick-emergency-access-on-description"), - Priority = (int) (airlock.EmergencyAccess ? TricksVerbPriorities.EmergencyAccessOff : TricksVerbPriorities.EmergencyAccessOn), + Priority = (int) (airlockComp.EmergencyAccess ? TricksVerbPriorities.EmergencyAccessOff : TricksVerbPriorities.EmergencyAccessOn), }; args.Verbs.Add(emergencyAccess); } diff --git a/Content.Server/Construction/Completions/AttemptElectrocute.cs b/Content.Server/Construction/Completions/AttemptElectrocute.cs index 05f0977b66..5c97d5e90f 100644 --- a/Content.Server/Construction/Completions/AttemptElectrocute.cs +++ b/Content.Server/Construction/Completions/AttemptElectrocute.cs @@ -1,4 +1,5 @@ using Content.Server.Electrocution; +using Content.Shared.Electrocution; using Content.Shared.Construction; namespace Content.Server.Construction.Completions; diff --git a/Content.Server/Doors/WireActions/DoorBoltWireAction.cs b/Content.Server/Doors/WireActions/DoorBoltWireAction.cs index fc1cf50cd8..80555f68f9 100644 --- a/Content.Server/Doors/WireActions/DoorBoltWireAction.cs +++ b/Content.Server/Doors/WireActions/DoorBoltWireAction.cs @@ -2,7 +2,6 @@ using Content.Server.Wires; using Content.Shared.Doors; using Content.Shared.Doors.Components; -using Content.Shared.Doors.Systems; using Content.Shared.Wires; namespace Content.Server.Doors; diff --git a/Content.Server/Electrocution/Components/ElectrifiedComponent.cs b/Content.Server/Electrocution/Components/ElectrifiedComponent.cs deleted file mode 100644 index 4ef07a0cca..0000000000 --- a/Content.Server/Electrocution/Components/ElectrifiedComponent.cs +++ /dev/null @@ -1,91 +0,0 @@ -using Robust.Shared.Audio; - -namespace Content.Server.Electrocution; - -/// -/// Component for things that shock users on touch. -/// -[RegisterComponent] -public sealed partial class ElectrifiedComponent : Component -{ - [DataField("enabled")] - public bool Enabled = true; - - [DataField("onBump")] - public bool OnBump = true; - - [DataField("onAttacked")] - public bool OnAttacked = true; - - [DataField("noWindowInTile")] - public bool NoWindowInTile = false; - - [DataField("onHandInteract")] - public bool OnHandInteract = true; - - [DataField("onInteractUsing")] - public bool OnInteractUsing = true; - - [DataField("requirePower")] - public bool RequirePower = true; - - [DataField("usesApcPower")] - public bool UsesApcPower = false; - - [DataField("highVoltageNode")] - public string? HighVoltageNode; - - [DataField("mediumVoltageNode")] - public string? MediumVoltageNode; - - [DataField("lowVoltageNode")] - public string? LowVoltageNode; - - /// - /// Damage multiplier for HV electrocution - /// - [DataField] - public float HighVoltageDamageMultiplier = 3f; - - /// - /// Shock time multiplier for HV electrocution - /// - [DataField] - public float HighVoltageTimeMultiplier = 1.5f; - - /// - /// Damage multiplier for MV electrocution - /// - [DataField] - public float MediumVoltageDamageMultiplier = 2f; - - /// - /// Shock time multiplier for MV electrocution - /// - [DataField] - public float MediumVoltageTimeMultiplier = 1.25f; - - [DataField("shockDamage")] - public float ShockDamage = 7.5f; - - /// - /// Shock time, in seconds. - /// - [DataField("shockTime")] - public float ShockTime = 8f; - - [DataField("siemensCoefficient")] - public float SiemensCoefficient = 1f; - - [DataField("shockNoises")] - public SoundSpecifier ShockNoises = new SoundCollectionSpecifier("sparks"); - - [DataField("playSoundOnShock")] - public bool PlaySoundOnShock = true; - - [DataField("shockVolume")] - public float ShockVolume = 20; - - [DataField] - public float Probability = 1f; -} diff --git a/Content.Server/Electrocution/ElectrocutionSystem.cs b/Content.Server/Electrocution/ElectrocutionSystem.cs index ee1965a91b..e8dc64e185 100644 --- a/Content.Server/Electrocution/ElectrocutionSystem.cs +++ b/Content.Server/Electrocution/ElectrocutionSystem.cs @@ -490,4 +490,15 @@ private void PlayElectrocutionSound(EntityUid targetUid, EntityUid sourceUid, El } _audio.PlayPvs(electrified.ShockNoises, targetUid, AudioParams.Default.WithVolume(electrified.ShockVolume)); } + + public void SetElectrifiedWireCut(Entity ent, bool value) + { + if (ent.Comp.IsWireCut == value) + { + return; + } + + ent.Comp.IsWireCut = value; + Dirty(ent); + } } diff --git a/Content.Server/Power/PowerWireAction.cs b/Content.Server/Power/PowerWireAction.cs index 374c1c41ac..43d1de6e4d 100644 --- a/Content.Server/Power/PowerWireAction.cs +++ b/Content.Server/Power/PowerWireAction.cs @@ -1,4 +1,5 @@ using Content.Server.Electrocution; +using Content.Shared.Electrocution; using Content.Server.Power.Components; using Content.Server.Wires; using Content.Shared.Emp; @@ -108,6 +109,7 @@ private void SetElectrified(EntityUid used, bool setting, ElectrifiedComponent? && !EntityManager.TryGetComponent(used, out electrified)) return; + _electrocutionSystem.SetElectrifiedWireCut((used, electrified), setting); electrified.Enabled = setting; } diff --git a/Content.Server/Remotes/DoorRemoteSystem.cs b/Content.Server/Remotes/DoorRemoteSystem.cs index 31fcacdaf8..986fb1071f 100644 --- a/Content.Server/Remotes/DoorRemoteSystem.cs +++ b/Content.Server/Remotes/DoorRemoteSystem.cs @@ -82,7 +82,7 @@ private void OnBeforeInteract(Entity entity, ref BeforeRang case OperatingMode.ToggleEmergencyAccess: if (airlockComp != null) { - _airlock.ToggleEmergencyAccess(args.Target.Value, airlockComp); + _airlock.SetEmergencyAccess((args.Target.Value, airlockComp), !airlockComp.EmergencyAccess); _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User):player} used {ToPrettyString(args.Used)} on {ToPrettyString(args.Target.Value)} to set emergency access {(airlockComp.EmergencyAccess ? "on" : "off")}"); } diff --git a/Content.Shared/Doors/Components/AirlockComponent.cs b/Content.Shared/Doors/Components/AirlockComponent.cs index b2fa7574f7..e5794f186f 100644 --- a/Content.Shared/Doors/Components/AirlockComponent.cs +++ b/Content.Shared/Doors/Components/AirlockComponent.cs @@ -1,5 +1,6 @@ using Content.Shared.DeviceLinking; using Content.Shared.Doors.Systems; +using Robust.Shared.Audio; using Robust.Shared.GameStates; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; @@ -23,6 +24,18 @@ public sealed partial class AirlockComponent : Component [ViewVariables(VVAccess.ReadWrite)] [DataField, AutoNetworkedField] public bool EmergencyAccess = false; + + /// + /// Sound to play when the airlock emergency access is turned on. + /// + [DataField] + public SoundSpecifier EmergencyOnSound = new SoundPathSpecifier("/Audio/Machines/airlock_emergencyon.ogg"); + + /// + /// Sound to play when the airlock emergency access is turned off. + /// + [DataField] + public SoundSpecifier EmergencyOffSound = new SoundPathSpecifier("/Audio/Machines/airlock_emergencyoff.ogg"); /// /// Pry modifier for a powered airlock. diff --git a/Content.Shared/Doors/Systems/SharedAirlockSystem.cs b/Content.Shared/Doors/Systems/SharedAirlockSystem.cs index 5a6d45d9ec..72e9428986 100644 --- a/Content.Shared/Doors/Systems/SharedAirlockSystem.cs +++ b/Content.Shared/Doors/Systems/SharedAirlockSystem.cs @@ -1,4 +1,5 @@ using Content.Shared.Doors.Components; +using Robust.Shared.Audio.Systems; using Content.Shared.Popups; using Content.Shared.Prying.Components; using Content.Shared.Wires; @@ -8,6 +9,7 @@ namespace Content.Shared.Doors.Systems; public abstract class SharedAirlockSystem : EntitySystem { [Dependency] protected readonly SharedAppearanceSystem Appearance = default!; + [Dependency] protected readonly SharedAudioSystem Audio = default!; [Dependency] protected readonly SharedDoorSystem DoorSystem = default!; [Dependency] protected readonly SharedPopupSystem Popup = default!; [Dependency] private readonly SharedWiresSystem _wiresSystem = default!; @@ -123,11 +125,23 @@ public void UpdateEmergencyLightStatus(EntityUid uid, AirlockComponent component Appearance.SetData(uid, DoorVisuals.EmergencyLights, component.EmergencyAccess); } - public void ToggleEmergencyAccess(EntityUid uid, AirlockComponent component) + public void SetEmergencyAccess(Entity ent, bool value, EntityUid? user = null, bool predicted = false) { - component.EmergencyAccess = !component.EmergencyAccess; - Dirty(uid, component); // This only runs on the server apparently so we need this. - UpdateEmergencyLightStatus(uid, component); + if(!ent.Comp.Powered) + return; + + if (ent.Comp.EmergencyAccess == value) + return; + + ent.Comp.EmergencyAccess = value; + Dirty(ent, ent.Comp); // This only runs on the server apparently so we need this. + UpdateEmergencyLightStatus(ent, ent.Comp); + + var sound = ent.Comp.EmergencyAccess ? ent.Comp.EmergencyOnSound : ent.Comp.EmergencyOffSound; + if (predicted) + Audio.PlayPredicted(sound, ent, user: user); + else + Audio.PlayPvs(sound, ent); } public void SetAutoCloseDelayModifier(AirlockComponent component, float value) diff --git a/Content.Shared/Doors/Systems/SharedDoorSystem.Bolts.cs b/Content.Shared/Doors/Systems/SharedDoorSystem.Bolts.cs index 35681bfd82..13050616e1 100644 --- a/Content.Shared/Doors/Systems/SharedDoorSystem.Bolts.cs +++ b/Content.Shared/Doors/Systems/SharedDoorSystem.Bolts.cs @@ -77,8 +77,20 @@ public void SetBoltLightsEnabled(Entity ent, bool value) public void SetBoltsDown(Entity ent, bool value, EntityUid? user = null, bool predicted = false) { + TrySetBoltDown(ent, value, user, predicted); + } + + public bool TrySetBoltDown( + Entity ent, + bool value, + EntityUid? user = null, + bool predicted = false + ) + { + if (!_powerReceiver.IsPowered(ent.Owner)) + return false; if (ent.Comp.BoltsDown == value) - return; + return false; ent.Comp.BoltsDown = value; Dirty(ent, ent.Comp); @@ -89,6 +101,7 @@ public void SetBoltsDown(Entity ent, bool value, EntityUid? u Audio.PlayPredicted(sound, ent, user: user); else Audio.PlayPvs(sound, ent); + return true; } private void OnStateChanged(Entity entity, ref DoorStateChangedEvent args) diff --git a/Content.Shared/Doors/Systems/SharedDoorSystem.cs b/Content.Shared/Doors/Systems/SharedDoorSystem.cs index 4e493f158b..c62d64889f 100644 --- a/Content.Shared/Doors/Systems/SharedDoorSystem.cs +++ b/Content.Shared/Doors/Systems/SharedDoorSystem.cs @@ -10,6 +10,7 @@ using Content.Shared.Interaction; using Content.Shared.Physics; using Content.Shared.Popups; +using Content.Shared.Power.EntitySystems; using Content.Shared.Prying.Components; using Content.Shared.Prying.Systems; using Content.Shared.Stunnable; @@ -41,6 +42,9 @@ public abstract partial class SharedDoorSystem : EntitySystem [Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!; [Dependency] private readonly PryingSystem _pryingSystem = default!; [Dependency] protected readonly SharedPopupSystem Popup = default!; + [Dependency] private readonly SharedMapSystem _mapSystem = default!; + [Dependency] private readonly SharedPowerReceiverSystem _powerReceiver = default!; + [ValidatePrototypeId] public const string DoorBumpTag = "DoorBumpOpener"; diff --git a/Content.Shared/Electrocution/Components/ElectrifiedComponent.cs b/Content.Shared/Electrocution/Components/ElectrifiedComponent.cs new file mode 100644 index 0000000000..f7fe92b826 --- /dev/null +++ b/Content.Shared/Electrocution/Components/ElectrifiedComponent.cs @@ -0,0 +1,131 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Audio; + +namespace Content.Shared.Electrocution; + +/// +/// Component for things that shock users on touch. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class ElectrifiedComponent : Component +{ + [DataField, AutoNetworkedField] + public bool Enabled = true; + + /// + /// Should player get damage on collide + /// + [DataField, AutoNetworkedField] + public bool OnBump = true; + + /// + /// Should player get damage on attack + /// + [DataField, AutoNetworkedField] + public bool OnAttacked = true; + + /// + /// When true - disables power if a window is present in the same tile + /// + [DataField, AutoNetworkedField] + public bool NoWindowInTile = false; + + /// + /// Should player get damage on interact with empty hand + /// + [DataField, AutoNetworkedField] + public bool OnHandInteract = true; + + /// + /// Should player get damage on interact while holding an object in their hand + /// + [DataField, AutoNetworkedField] + public bool OnInteractUsing = true; + + /// + /// Indicates if the entity requires power to function + /// + [DataField, AutoNetworkedField] + public bool RequirePower = true; + + /// + /// Indicates if the entity uses APC power + /// + [DataField, AutoNetworkedField] + public bool UsesApcPower = false; + + /// + /// Identifier for the high voltage node. + /// + [DataField, AutoNetworkedField] + public string? HighVoltageNode; + + /// + /// Identifier for the medium voltage node. + /// + [DataField, AutoNetworkedField] + public string? MediumVoltageNode; + + /// + /// Identifier for the low voltage node. + /// + [DataField, AutoNetworkedField] + public string? LowVoltageNode; + + /// + /// Damage multiplier for HV electrocution + /// + [DataField, AutoNetworkedField] + public float HighVoltageDamageMultiplier = 3f; + + /// + /// Shock time multiplier for HV electrocution + /// + [DataField, AutoNetworkedField] + public float HighVoltageTimeMultiplier = 1.5f; + + /// + /// Damage multiplier for MV electrocution + /// + [DataField, AutoNetworkedField] + public float MediumVoltageDamageMultiplier = 2f; + + /// + /// Shock time multiplier for MV electrocution + /// + [DataField, AutoNetworkedField] + public float MediumVoltageTimeMultiplier = 1.25f; + + [DataField, AutoNetworkedField] + public float ShockDamage = 7.5f; + + /// + /// Shock time, in seconds. + /// + [DataField, AutoNetworkedField] + public float ShockTime = 8f; + + [DataField, AutoNetworkedField] + public float SiemensCoefficient = 1f; + + [DataField, AutoNetworkedField] + public SoundSpecifier ShockNoises = new SoundCollectionSpecifier("sparks"); + + [DataField, AutoNetworkedField] + public SoundPathSpecifier AirlockElectrifyDisabled = new("/Audio/Machines/airlock_electrify_on.ogg"); + + [DataField, AutoNetworkedField] + public SoundPathSpecifier AirlockElectrifyEnabled = new("/Audio/Machines/airlock_electrify_off.ogg"); + + [DataField, AutoNetworkedField] + public bool PlaySoundOnShock = true; + + [DataField, AutoNetworkedField] + public float ShockVolume = 20; + + [DataField, AutoNetworkedField] + public float Probability = 1f; + + [DataField, AutoNetworkedField] + public bool IsWireCut = false; +} diff --git a/Content.Shared/Electrocution/SharedElectrocutionSystem.cs b/Content.Shared/Electrocution/SharedElectrocutionSystem.cs index b228a987af..e36e4a804b 100644 --- a/Content.Shared/Electrocution/SharedElectrocutionSystem.cs +++ b/Content.Shared/Electrocution/SharedElectrocutionSystem.cs @@ -23,6 +23,20 @@ public void SetInsulatedSiemensCoefficient(EntityUid uid, float siemensCoefficie Dirty(uid, insulated); } + /// + /// Sets electrified value of component and marks dirty if required. + /// + public void SetElectrified(Entity ent, bool value) + { + if (ent.Comp.Enabled == value) + { + return; + } + + ent.Comp.Enabled = value; + Dirty(ent, ent.Comp); + } + /// Entity being electrocuted. /// Source entity of the electrocution. /// How much shock damage the entity takes. diff --git a/Content.Shared/Power/EntitySystems/SharedPowerReceiverSystem.cs b/Content.Shared/Power/EntitySystems/SharedPowerReceiverSystem.cs index 2bc2af7831..b7ba2a31c5 100644 --- a/Content.Shared/Power/EntitySystems/SharedPowerReceiverSystem.cs +++ b/Content.Shared/Power/EntitySystems/SharedPowerReceiverSystem.cs @@ -1,5 +1,4 @@ using System.Diagnostics.CodeAnalysis; -using Content.Shared.Examine; using Content.Shared.Power.Components; namespace Content.Shared.Power.EntitySystems; @@ -8,6 +7,9 @@ public abstract class SharedPowerReceiverSystem : EntitySystem { public abstract bool ResolveApc(EntityUid entity, [NotNullWhen(true)] ref SharedApcPowerReceiverComponent? component); + /// + /// Checks if entity is APC-powered device, and if it have power. + /// public bool IsPowered(Entity entity) { if (!ResolveApc(entity.Owner, ref entity.Comp)) diff --git a/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Airlock.cs b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Airlock.cs index ff6fc1ece0..37e5cd6e6a 100644 --- a/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Airlock.cs +++ b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Airlock.cs @@ -1,5 +1,6 @@ using Content.Shared.Doors.Components; using Robust.Shared.Serialization; +using Content.Shared.Electrocution; namespace Content.Shared.Silicons.StationAi; @@ -10,16 +11,84 @@ public abstract partial class SharedStationAiSystem private void InitializeAirlock() { SubscribeLocalEvent(OnAirlockBolt); + SubscribeLocalEvent(OnAirlockEmergencyAccess); + SubscribeLocalEvent(OnElectrified); } + /// + /// Attempts to bolt door. If wire was cut (AI or for bolts) or its not powered - notifies AI and does nothing. + /// private void OnAirlockBolt(EntityUid ent, DoorBoltComponent component, StationAiBoltEvent args) { - _doors.SetBoltsDown((ent, component), args.Bolted, args.User, predicted: true); + if (component.BoltWireCut) + { + ShowDeviceNotRespondingPopup(args.User); + return; + } + + var setResult = _doors.TrySetBoltDown((ent, component), args.Bolted, args.User, predicted: true); + if (!setResult) + { + ShowDeviceNotRespondingPopup(args.User); + } + } + + /// + /// Attempts to bolt door. If wire was cut (AI) or its not powered - notifies AI and does nothing. + /// + private void OnAirlockEmergencyAccess(EntityUid ent, AirlockComponent component, StationAiEmergencyAccessEvent args) + { + if (!PowerReceiver.IsPowered(ent)) + { + ShowDeviceNotRespondingPopup(args.User); + return; + } + + _airlocks.SetEmergencyAccess((ent, component), args.EmergencyAccess, args.User, predicted: true); + } + + /// + /// Attempts to bolt door. If wire was cut (AI or for one of power-wires) or its not powered - notifies AI and does nothing. + /// + private void OnElectrified(EntityUid ent, ElectrifiedComponent component, StationAiElectrifiedEvent args) + { + if ( + component.IsWireCut + || !PowerReceiver.IsPowered(ent) + ) + { + ShowDeviceNotRespondingPopup(args.User); + return; + } + + _electrify.SetElectrified((ent, component), args.Electrified); + var soundToPlay = component.Enabled + ? component.AirlockElectrifyDisabled + : component.AirlockElectrifyEnabled; + _audio.PlayLocal(soundToPlay, ent, args.User); } } +/// Event for StationAI attempt at bolting/unbolting door. [Serializable, NetSerializable] public sealed class StationAiBoltEvent : BaseStationAiAction { + /// Marker, should be door bolted or unbolted. public bool Bolted; } + +/// Event for StationAI attempt at setting emergency access for door on/off. +[Serializable, NetSerializable] +public sealed class StationAiEmergencyAccessEvent : BaseStationAiAction +{ + /// Marker, should door have emergency access on or off. + public bool EmergencyAccess; +} + +/// Event for StationAI attempt at electrifying/de-electrifying door. +[Serializable, NetSerializable] +public sealed class StationAiElectrifiedEvent : BaseStationAiAction +{ + /// Marker, should door be electrified or no. + public bool Electrified; +} diff --git a/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs index a6c57f5940..5c43b643b1 100644 --- a/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs +++ b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs @@ -1,6 +1,7 @@ using System.Diagnostics.CodeAnalysis; using Content.Shared.Actions.Events; using Content.Shared.Interaction.Events; +using Content.Shared.Popups; using Content.Shared.Verbs; using Robust.Shared.Serialization; using Robust.Shared.Utility; @@ -13,6 +14,9 @@ public abstract partial class SharedStationAiSystem * Added when an entity is inserted into a StationAiCore. */ + //TODO: Fix this, please + private const string JobNameLocId = "job-name-station-ai"; + private void InitializeHeld() { SubscribeLocalEvent(OnRadialMessage); @@ -22,6 +26,22 @@ private void InitializeHeld() SubscribeLocalEvent(OnHeldInteraction); SubscribeLocalEvent(OnHeldRelay); SubscribeLocalEvent(OnCoreJump); + SubscribeLocalEvent(OnTryGetIdentityShortInfo); + } + + private void OnTryGetIdentityShortInfo(TryGetIdentityShortInfoEvent args) + { + if (args.Handled) + { + return; + } + + if (!HasComp(args.ForActor)) + { + return; + } + args.Title = $"{Name(args.ForActor)} ({Loc.GetString(JobNameLocId)})"; + args.Handled = true; } private void OnCoreJump(Entity ent, ref JumpToCoreEvent args) @@ -88,41 +108,56 @@ private void OnMessageAttempt(BoundUserInterfaceMessageAttempt ev) return; if (TryComp(ev.Actor, out StationAiHeldComponent? aiComp) && - (!ValidateAi((ev.Actor, aiComp)) || - !HasComp(ev.Target))) + (!TryComp(ev.Target, out StationAiWhitelistComponent? whitelistComponent) || + !ValidateAi((ev.Actor, aiComp)))) { + if (whitelistComponent is { Enabled: false }) + { + ShowDeviceNotRespondingPopup(ev.Actor); + } ev.Cancel(); } } private void OnHeldInteraction(Entity ent, ref InteractionAttemptEvent args) { - // Cancel if it's not us or something with a whitelist. - args.Cancelled = ent.Owner != args.Target && - args.Target != null && - (!TryComp(args.Target, out StationAiWhitelistComponent? whitelist) || !whitelist.Enabled); + // Cancel if it's not us or something with a whitelist, or whitelist is disabled. + args.Cancelled = (!TryComp(args.Target, out StationAiWhitelistComponent? whitelistComponent) + || !whitelistComponent.Enabled) + && ent.Owner != args.Target + && args.Target != null; + if (whitelistComponent is { Enabled: false }) + { + ShowDeviceNotRespondingPopup(ent.Owner); + } } private void OnTargetVerbs(Entity ent, ref GetVerbsEvent args) { - if (!args.CanComplexInteract || - !ent.Comp.Enabled || - !HasComp(args.User) || - !HasComp(args.Target)) + if (!args.CanComplexInteract + || !HasComp(args.User)) { return; } var user = args.User; + var target = args.Target; var isOpen = _uiSystem.IsUiOpen(target, AiUi.Key, user); - args.Verbs.Add(new AlternativeVerb() + var verb = new AlternativeVerb { Text = isOpen ? Loc.GetString("ai-close") : Loc.GetString("ai-open"), Act = () => { + // no need to show menu if device is not powered. + if (!PowerReceiver.IsPowered(ent.Owner)) + { + ShowDeviceNotRespondingPopup(user); + return; + } + if (isOpen) { _uiSystem.CloseUi(ent.Owner, AiUi.Key, user); @@ -132,7 +167,13 @@ private void OnTargetVerbs(Entity ent, ref GetVerbs _uiSystem.OpenUi(ent.Owner, AiUi.Key, user); } } - }); + }; + args.Verbs.Add(verb); + } + + private void ShowDeviceNotRespondingPopup(EntityUid toEntity) + { + _popup.PopupClient(Loc.GetString("ai-device-not-responding"), toEntity, PopupType.MediumCaution); } } diff --git a/Content.Shared/Silicons/StationAi/SharedStationAiSystem.cs b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.cs index 348b0b0465..7fb00d9ade 100644 --- a/Content.Shared/Silicons/StationAi/SharedStationAiSystem.cs +++ b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.cs @@ -4,14 +4,18 @@ using Content.Shared.Containers.ItemSlots; using Content.Shared.Database; using Content.Shared.Doors.Systems; +using Content.Shared.Electrocution; using Content.Shared.Interaction; using Content.Shared.Item.ItemToggle; using Content.Shared.Mind; using Content.Shared.Movement.Components; using Content.Shared.Movement.Systems; +using Content.Shared.Popups; using Content.Shared.Power; +using Content.Shared.Power.EntitySystems; using Content.Shared.StationAi; using Content.Shared.Verbs; +using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; using Robust.Shared.Map.Components; using Robust.Shared.Network; @@ -24,23 +28,28 @@ namespace Content.Shared.Silicons.StationAi; public abstract partial class SharedStationAiSystem : EntitySystem { - [Dependency] private readonly ISharedAdminManager _admin = default!; - [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly INetManager _net = default!; - [Dependency] private readonly ItemSlotsSystem _slots = default!; - [Dependency] private readonly ItemToggleSystem _toggles = default!; - [Dependency] private readonly ActionBlockerSystem _blocker = default!; - [Dependency] private readonly MetaDataSystem _metadata = default!; - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] private readonly SharedContainerSystem _containers = default!; - [Dependency] private readonly SharedDoorSystem _doors = default!; - [Dependency] private readonly SharedEyeSystem _eye = default!; + [Dependency] private readonly ISharedAdminManager _admin = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly INetManager _net = default!; + [Dependency] private readonly ItemSlotsSystem _slots = default!; + [Dependency] private readonly ItemToggleSystem _toggles = default!; + [Dependency] private readonly ActionBlockerSystem _blocker = default!; + [Dependency] private readonly MetaDataSystem _metadata = default!; + [Dependency] private readonly SharedAirlockSystem _airlocks = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedContainerSystem _containers = default!; + [Dependency] private readonly SharedDoorSystem _doors = default!; + [Dependency] private readonly SharedElectrocutionSystem _electrify = default!; + [Dependency] private readonly SharedEyeSystem _eye = default!; [Dependency] protected readonly SharedMapSystem Maps = default!; - [Dependency] private readonly SharedMindSystem _mind = default!; - [Dependency] private readonly SharedMoverController _mover = default!; - [Dependency] private readonly SharedTransformSystem _xforms = default!; - [Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!; - [Dependency] private readonly StationAiVisionSystem _vision = default!; + [Dependency] private readonly SharedMindSystem _mind = default!; + [Dependency] private readonly SharedMoverController _mover = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedPowerReceiverSystem PowerReceiver = default!; + [Dependency] private readonly SharedTransformSystem _xforms = default!; + [Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!; + [Dependency] private readonly StationAiVisionSystem _vision = default!; // StationAiHeld is added to anything inside of an AI core. // StationAiHolder indicates it can hold an AI positronic brain (e.g. holocard / core). diff --git a/Resources/Audio/Machines/airlock_electrify_off.ogg b/Resources/Audio/Machines/airlock_electrify_off.ogg new file mode 100644 index 0000000000000000000000000000000000000000..c88d00299e9215a647c144f514a18d7dc5af7a87 GIT binary patch literal 9989 zcmaiY2UHYKv+s~Il0=fQWR|=H5tS%$$qPu%IVu^+NRT9wbIxgzjDUcOtmGU;l1LH} z5CM_&X7T^s?|b*XbMKs;TFmV3L zgUUX9gmKM*sX}@~#u9V^fD8c4*`TD!w#v}bltQkj87WF=s#h>NBPF_*#wrem`d0@L zvAzia*gyyuL45Isvg3%j9Svu^dx5xv`rUE}UX0d?IKlfP4lCEPrZOkj5hy!8i2)7( z8cSM_ z_?jl*s<7!tR<)hDCIKEJ;+r}DbOhJufPj0E#ig|-lf_4ikAjwExPzkp9t#45fCc~* z6RDKzsRrvAhR4}7e)4KjijE7*YwM`#f|r+xp0~}cx7Vz9pg~52(d$5i*AYf@5hf=Q z7BrFnwBLctC+K#4bO;7ez$%`$1}$QtEBYc{gcTlHg9%upO#&fEVu23^wo%HV|J=0UeEv-VIRTkX82oG+To-oBzE@+xKw;(x5Frx-oooW0Oa)eRSu= zyS8v2+S}3y-d=YRMGujW9uL5#=qcBqqB{Ib^~S%PfCdBrNW&O<-5B~oYasY0-9`00 zBxXI-WUm;mzS%<^o zq*?0)l~mc2@1k|GIom2TvadbpJVLt$`Vu;j*;|k~mgO;`Oq^BvmwHN(jfbq90LN%I zb4XFN7T`RGi7dRzd3|uL!C2NtMH>}JMW%0mtLYiJw^P?c_K+9`qL^0{MDdH} zjXaN9aV4kH<{3kt(i8+7TKYGlK&L{i6J&5{uY)8q!+ii+4o1a)I&PnBl>GMif3(p9 z1}zG9u#F4xX$wo}>geiuyBMTzayuBEB?#fcvj^kHiION zr)hT4S(TZ2+m%Ix|1EOtW6CpP%A;a7qvE-u(;T9+s@jU22WofP|JU|kk)!C&1~xEq zu ziT4m6t{}K>%BhCEU>A#rki0K5R$jl052ihAKnnmuV12L;H0~qH{RMI(FoN8aK5@>{ za4g{_hBOrbSP~-$p%E#F z5$Hw&VgRra2sFsfIAf@iKj_v}rnr;ib8l{@rFCAS< zdEJ}3lWA(Y%`T%NHuE~Vi`2T)EjA0(L3(Lk%fe~~;NuL)^_oo!G@EfT$@oW<8r8L^ zJG!$iqFSE1TDmp{I=TklHU=lUdNYA4AXi&${-&;Oi|+i9i*8!rs;91rp3VG;t^swB z(QL%(ao{QqTJr3)7s$1kv9W0NTIO=da&RoFsLJB1s;aDNajB|B8Wn9-6;%y1*j3fm z3^cr|u65o4xwREl4ZKxVywwdgXH~pAEfrPm$bp8s?Aq#`mOY{#-ktU*RkgL%4d2n+ zcH|DqZKqu@pbR=#R{gELvc27Pr`>I+#f71`>RT80;QP9PhP|D3fhI3zEnTn06q7YQ z@Ek5?K6yqb5e+W)yOC!Dpn!?r;-ill+Q4OvuJqs->X1ju;%|_DCJT2!Ms5R=DA20! zgkaQZ0p)gfZ|&Ht_!Tk1$Cn^BFwoeb9FQ(#=D`fPivi#=Z&GQKarZ(z$q?TlB|0!% zW)F3EFGGqZ+>tqDiW>#diC6B+Nv43?LsKRYc!i~!aHqnQ8H7`P*_7ojq=Xvoz?U*% z=vaxGGK?d)A`{vyu^v$-C~ZPBKvA0oC8Vj+@cL$ICs)`89ozwlR$kdlZ4?hG*LD&un{h-lj9esUvOM6(nJL5zkYVN0Ii2Od z_pg&%I`W}rERksC-1VtRpz@7RhH>I46PBQ;Bt#sz!pOO;EX@&QWFcakH$HhdiyluI z)}VE$fNuzomu*Lnz^oI31xSYw*c6~s2s&(Kq7Wm>4rJ~_;@kwXL*ks3?y9m-sP2#q zK6~?sI277DBaY8rO0B}p*Zar`3I$KW2i6_eVT-F4-HSm;Vn6`Mfl-WtfO!X(wv;Ap zjHZOjij1X{2J}lQl@(}P8V^!gZd$7m87^qJCY&1@K?YZ5F9oY!LI$v&a~@04X8pMVunotCx7v%~^0XJP_R(K!O`J;`-6b`JW;^pf|u#yP`7@ss&HDCZ4I)Phv;)6ENSjIJj_6IY>jAg9o zj3E)Q;`#&#QL1x`Of6}AKfZG9Yi6+6mc6z%`ojPL`l0}h7G^m(h$=Kjn8QIg{2dEV z_^&atdz*iu1p;dG@4OUE*=uOw7lLEZ+aSoet|@kqBKTXtU4t>40xacHK*@i{QYb(j z*X3Ob0*y$}G-$>(RIe!lX0*AkCo}(Di>?Jhh+?6$FzXgu@c@gn$m)A6P5VAL5JC(9 zZgY-1(3w6+Z%%lcN_c`hnI%6tB1T-X-bRVGmu5NzR!XIfaN5eTjMLJ{wSvQXYEmA- zxe}jExYsm$4}qV95PU$8j9EBT8iR_a4^$M64FwA7-j2bHv9Z5W2oVw!ehl}RaKHk{ z!uyC5qx6X>D62w?EbjsO#^!x^A;d3UG{q8a3BAQJ`RoM=hhQ^D^Rvxo_s0k->+f}fDr(aNFXdMS>o}eFK;A}C6XsmBvYn<@CASsjF1~Z2pdjRRFrLe zanBkSo1Arc$%n7l?AL5`hmZgFQw95){`=J|E&G>^{%S_6frfm^=Y)xJi3$jF^YHQT z2?+}e@C(9(1qEO*A^zpDp}F~i>FJ@~nNKsr);O`b5?`qB-k9O7#CIYe1hsG~yD>)~ z3U#>h<#F~J=<08~CHK;a#fb49F!f)>VqjzV7-*P$_ri1+bqd^qKrHH?u6aDRo3t>G zd*o2hB=Lj#1|8wB$J_5eI)*wVrF=+GU+&`&AHePXhs^ybHpS?d1fQL5o}hX?C;fE& z^}0wiEm^ZozmdHxOtet{h3&(Azxt$P<(Ef(eJdN|-4>Ybi0KPEVSiC)3*#0({bmjv zp2812jgxez0Xdf$gTty}7(*9=Q%byej6p2Y;*ZN7@5apNg<1~uvE1s^D!z9C5R_8~ z1od!JvuRB7xgFSJ{=$IPyw0n=!RhF7R%QQsOqg}4Sj~jNyO{gw`rUMTBQ;7x`pj6Iic~Ud1v00|$W?_V7(ZOV3+xIv z|7=xO2fn8Juqs>d;;~s_3Eey4|n*RkQhU!ny>6e2lXy(Y;mNOm@p7Ok5AgN zQl?z-2(wbU6a9$fyxNGF^at)bMO))x<4T0k4z->pBi}DmaNTN*Buy8c)Xu*2T046z zszK0O9kyLSBXN*BG{3Tc`Q^)jBcMtRbwR!y^=pYJ`&sf?3ew) z%~cHBjn48xetzUGerD{1Z_q|G;4IV`*A%#V71yeDtOxMj(;RvCh3u%jS15h=b6)PS zhZY<0C;XD5tOukuuV!j+UKMI%67vtH+&<>M6o=fW2*QiPixO0RMm>1;M`h>A9qGJq z!>=OpWfX1r%W|LN)pxNNA1+K`as4N&SgXO@0tKPc_Lo{RWkq?Y4b`RcifqpqWc|_F zAUU>iNL{)zAz-X(smW|nahX-v?l z2Zle)Tf@jvh-KM-@%!Bvws*d5h^MPv+hms3n+nOYT|docZ%4<<*m-nP%|m`A@``SqZXhv-YUfdfwY5 z@FN9s_cgJA-9M3#T&&ZXR#goN`seXepQ+xsN;0Z(<$FB-6=Ka5Ti<`5WJ znDXR%a2ch}&vgw=ff3tW#f?r>C@X%MuiG$gbuvX{TB|wU6WrGGEYcM9qmd9}A!&Ek z!*pCrk&)a}`4@%XW_%n~yFsAKYr9c~8-j~hbQ+(84`-#`-bspZs-|B10Ley8S;a`iO%IE zIjhl3qT~{`6}u>I!;( z#3AcQE1SNAOH{qgL`ur{{_H)ki)hJ%qx+PG4!>@P5K=8?Fpj*2Ty&14R$(^8FyY#y zM{Y}L`p55i^{tjKmOUN06*q60aQ3Vw4brj7B%_3PXKY$XdslD&GVtKdslU=bn0`&C z*aEuA9?-sd686GOJpy8ZmzeLoQ9`z(=*6~eJ-`ua?EkROTYrd&KHbMebf)>4`WZH0 z`t9pD`EVAlnNW zt8z&u_T+3csFdTaY_IzjTqCWQ#txv-3(_1@*i}^PT3uL5>^}_besb~s{Fl{lKJUi? zKs|q+huqgoD#e#b#o}49W;UG2u#kfCErGeX8kyMRP2+YK|(y4XVCyv4{mxs{mx&q+&Qm1hw{hjuKX4<#Vk zuCtnzh9}ZX+Vb2}k@gT%u*D_y7tCqWH{@bLn^xraI7j-(!_&3PZ|w)8s6&i4-u?^a zxK9#~S`B})Wy4O>f}2(bG&y+2o7q_I)iO~$#W!O2G2-{FtV=JpN&Oh@Y$;~x-!Gs2 zn5}U;39o{-_EkK_JIp&V4#@r6Q}#I%+%x$vWt|fJH_2dlM*VI3(TT$;Ug@l;#N(dYIGld$?@O3bfeNbprbpmT?P5sPl`T zJLd;K(=t1^z0z2bHBz%i3mcjm-*lTu8*fM33Z;10(toz+y!+~>>zCH0ou%QAD0y35 zDrWkI`cO6?r%tHwsxPzA7s@j*je^`wW%@?D%vj@^lEZ@p=t3&`de=v&oTc+4Igct zSkcL)C^s8-l#o#J()yMPSqNUxr>`HbZg#TddGav#GmdHJZrC{8ggnN(?X zJ>LW3%4lb2lwT6)@@w&^DO&CM!-Zq-*9N_7zWI!Cq_OW_d?}G0ArB0j&GfO7%ahT# z%}C)FA6V_|L0N~psJ^6Og36h_S>;O7(c`WE^uUmtE_kS5_@$QSPFo~4W*$a;7CWhi z%l#4}R_mG7bQ^nlKl}B1iqt#A;VFUSiinI~-u?&)1`?)V|CYIL%~Y9l~rlV~@I6{nTNZ zN_byM9{groQuhejJa~B#Jo%|hVCd%>mImc5^$FjOtLxs_)wIZz)8>(Ez8JWAwou&8LFYk-kub$#bHG%E{pd>B`PsXuEqXg%-CP=;`SmY>LeAi)sJ3xXk_^{QS*Zi^QdZzIP?&8`4Kr z+P<#XBfCS%B5KUNB`OtuYQ8J9kyH4|?1E46dHkc{Vw4Ael*s*}4@`(<4whzfZdDH% z*BXJ=;Bf|44#3ZB2e&k=*f)RPq14mA*CZz!{qM>Q*p_hj+QXNTE zCnh&s(=0&YEty*TT+41!6Lv+vd~!J^u=I^>{R+puu_rp4P4sZYx7U6`R4|e~HYU&N z+llh?9lJy5?p2t!Si0S9+Pm59uhsp3{k~8s$MdMZE76}O)@5XH$3oa8At_*!frHs> z#<0CWPKEzzXQiq^uf^*!@@GS|gi@a#*kL(M@f`PEW)MciOBVj@qr}dZ4e#=9ETrpw zcMDf6>>=XnLP8axw^qi((W|uFV(kI9Tc3dv?AqydW$vQk6eF+ zNmmf2rRhu_*E4cJ`W_t7=lx)#H8=C_ zTCPy{z04arUUK5&iT#zHZ~Z#GRy?`Rjz?D~>z`OW*#Ee(%cGrNF)A!-=4X5A^mMbs z@K0Wa{l)2xDt1TW!db@WgJJLiNdhWg4>N3j-Zqi^+k3?+n`NvQlGq7=Kf-N}yQq1e zZspSxQd*1})L)|{JzZk?i#PPEQfQ#F*wy9cQcKF<0;;>-q^XgyBcg5I8Sm$?ndu%P z2=!okyf~QhSZlFaacVv4>m}uR4eyVMq97iB3N0bhJyu~z*-Y&*X}!dVue&T@8oKzo zFZ{WcOQ2Si;jPGNR^jTfQCpFwo7^jZK9BS~ifoDR5qqpFkrTj(RI=K#&i8#?dqbC^ zJ|K5jb*rNY=GMx|j}dUuniNu2yr#^=DK3AMzvXV&?O*i#K9g;28U-$J{ks8s+VbDO z8?Zo<_X%Md!En##nc4ZdX{)7ARF_vVyhAj=u&^Itq0@^?)zy!WKNd9ibwWKpNlDCEXTbOxnrN|J zdd~577bAFHdQ&<_ z`(#;-RGjHgt>1G!75I!eHDbj&ub(H#yo{@VUgbVcNV&gLU`&eDNwMOF$YQC&4;nab z49d{;5b(M;R@`SBh4ld!SR$O>2!8&=_aNrLAvMR)qiIGdyjV}!(>fvp^XSq(03!Lr zqsvbNKUt!!)90z9L@F$`WqV+V@zT#JKQ?%Tf{QKi^qYO+$zj3~y1t>_7XpR?yu5U=-E$7We0f)g0C3pkq9$V3 zQK1e5`B5DNzt>nf>@cJ^qB`uasS{!#L{)Jw{|tYEntnR}%z_|tPv_jyA|#rD zWs`0jFThqW^l-uf{Hm+{^L^-sq%PO)AwZHqEl;aUV_LA+X5b~=YE+h6w1*m_u(i6N zE_1KMsyfsjoBgp|Ikr#WvfM0TFY@z4DBbH4%|Hax1@`DWrxLqKdlq~SXxx_~*#>HJ z-{Z<>{I7V3c#kA2+LAhepmxvge7HJxTJ&47MLTP)v}|d54vx}Psc|-}>cvoNZrbR* zH{DpHra|Wyca}He1USyJefMpHME}&%p9BOuq(l;ER-JCqV6C6rh`yovuAA(q5v!BS z>UrE9%>7RcbuUwyKKRhbg%4E-7>z&UT^{AMec!Y4!)4|^^38C~s^z)Q5P5sHqI!kD zPFb$bi^oes+3$x2+N&it#UF0EeOmxXH|_cFULZ}qezzenSt%d&`iQL z6Z76xG#V9@wYR@iK62L8X?k^&QOTs6gKm>K4KXK;2uG{H`dhXnSwt`xq2O;dWr= z#9c+``sXS&X4v2gP^l>tndMU|7`Mvgd*9|D?dA~QTw zVI3bt3tF@i<+@IE3))+c7Fow)nGP+={S_aF;cn8o!&NGOGMQwYnC)A?#ol^n_Z3yk z_ufM@6Q{=abM?|})i+z7+C@Hx9!AU3J>EisvgJB#AkV<_`%AJHw_?+$;~y+9qdacl zS#)#rb?YmZ3Cf+V%so$RaqZ^sY4Gfe)B zO}5Kp*+^fYKG&4j4w)H=SK$;VIpQnVB)qY33THN#{_W851s3Sg;LBsOhyOVB5kX{h zA1^C{yb-sDH}MK3N4wki$e8IvN1eS^*t8N;J~wx{=kM`H?ly79q9kzTE@hF+mt>3i zV>_DE$di{|`FItM#W_l@291_E$2BLr--iypp_j>9!JFrocf>edsMEhUhV9MruvtmB zq~{+_s8pOV)gN2@_7|w^U(vT~#*@b1^GZt67v~oq7%G#zD-!AAZ{j(eb@O)bq)|i4 z;!f(DJ0~%}{*dQ9_wtAj-sfTY>a4Ep^TY4i+0%03TFR$$I_w#5`;OMLU^nuMyIH}X zbw!@+H{T$Ka-PHzt;}!)xjde?YthAn(BFENZXB#Pc-cHK8mKR!@I0O&!;$WOpB2|S zvnn8I5cflonM^w3)YG}qKE(9Cf>b15vfOY6EzPgP#_78?ySs~564~b|C_nbz&~a-VuU4W}ox(JcBG)Y`@;gzB3xJO+ZE(ivDe0{ZVi7Wx&z-TD^gp+4<~o zp&8yp*X#NA-NBFV8U={81&EQGzYc`thmV7P3Z-_q(SAHEd>tH<+G(pr!_wHABV~@g Jb<1i8_&>kkeoz7lH{C` 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 Y)Lf}KqamXo7Nx|@V3)fW?GMEMAE{iGzyJUM literal 0 HcmV?d00001 diff --git a/Resources/Audio/Machines/airlock_emergencyon.ogg b/Resources/Audio/Machines/airlock_emergencyon.ogg new file mode 100644 index 0000000000000000000000000000000000000000..6c8b54a28459d7eccf88ef87b5ee70ef8e6d056b GIT binary patch literal 10094 zcmaia2|SeF_x~OHGL~#9BZL@?tZ9@iDU2)5hPSxO5+$i5AR5M@b-WD>G3 ziK2vTpAu5m|1*5P-|y%D{r_LT-}Ac9o%`H#?>YCL^FHS}_rcKF`7)pae_uzK4jOec znA5OhumCS#I~PAn7mV=Y?;(M({YE{^kTUb%7iA`e()tRm%4;U#xbTb$4 zYtn|k&VuePb|(Am1$6}FWaMOIlw=eH#j%bKczYL5XTb}e0WQ8?o*s^#{zwYnW6;Tw^AX$@~ zbdbd4Jn`VPWNk{TT_!dyIkuhG{+=xPUzMPO12+IPfFRBoS1_yN+JkoH6^rxDMY|ZB zE*7M}V>E?ke6@bU-m~agk(*}^Qj~$koEAVTRMQrU=E71cyW2uByij!u;oBipoaxIX zQIdO;Nv=aMQcrHaFv&o9zN8>dc|rVHp9VAP*#JgQcG$$eqKVEr)UO9Um-%My>!a%MtI%OJ}fBb0v z7j!;#RLo;4;6PD{AYYN@Vj`2G;c{4|u+fLxdKqW`Bj znWs4Z??vrehXhcAbos^y@y18w0#@XWuN3{hhC2XcQ#GtqyRU+lpTZlzvry6U*L<6- z_ijy(?O#Tqm>mE$Swy=J;w_{NENakK(bP|6)K7mDQUygL|MPWYA1}~GgtDAcTnP;F z3AX!cAwX<-^BB&<4in)04)`pt9Zxzxu8~T za)wyVbK?Vkf5U=wC9|g${TZ4O`ys>aIioey`s0xK*E>c^-+#kL4YHfWD864ao9$PD)^;P-j95q#ld%{i@xY@XqY64C zsM8(UcaoSi-%eyPS2i0CJkBeVp?}wL7d}ofa6%Lqh(!~dF|g0bKo|UqxgS# z4#h=|qvNKv6KVeAIl1C-Urxsf>m-VpC!PpSagI$VJ<6UZ`|p3QmFrh z!~Zk@04)h{-TgRXghdTw6^F4XoUzLP>@g5^SV4bK0aENk0FD443>i6!{f=*fhNp@d zgY2vbZ62B~?=^2!F}pk*&2rp7L0wFxJ`vppU!B5=b8G5F-WOGh6J&W+WTi86ngI%X zG{6V|f^3KEYhK?TowvD~J+h2h$sK4hV$y&P5|zR$j}$H9u%FH>7|?lJn9QqtC##Ud zKDHd11n8lgIj=8)8>YqufE^smgp5wc_8?~yu${6q2rLF&oO!ti&A=bkDNC0X$&Mr< zF83hcAfmd}XEG!E)Wrc1Y=J?yhPZ;m1;8!_ro2UZlN5BhM0GhY^l~|la_WyhRCuSL zXk?7*;=~Obmex_F0|6jn*m}`Qwamj^@TV^8iQl4V>vnm@Y)UtUtz$ z!`0%();(}3VW0hR)~1eQ8#r^GaLdu?&%eSx^HMmE4&x!J?TDjo9ez^WCEdj}zoax> zytI^5TI*3-QEr+4tu(*1v)Z||;&EqnWm$#$B1EkyDXo?&EtM*(e!NvGwOCtH+ECtE z{UoEJY_aw`bDPv+gLi2~MOpO{h1yWQNcLH5kO?h9b`_N^G>{q^JQo{$x@$cU1*Hqk z5?!yJbXI>~Y&iK0FJy$ne@wQXHih=#aWyd8awEFh=J{ru8}28pg_ zNRaFV*$eSP24OvZ3L<1xmotaicWf~Bx{Z^4wv?xT;R`C^jBny0Y``ek;Otb(6OyDN zoQ459p*gP0>=NyQ{_NNV!9rtMIw3y;Ogkd^62?_1c}RjRXdI{0k(tDSxrR(0z|!Xt zFJavBl1H#^RYgN~%YubG7#CFXfQ2iGJY;e2kUhKHT%kjc4kPgyg#fXd%PnNpzz_?$ zbTKHCZV1Q)1M1qOLXOKiq#B47v5-d>BU{U5=_xycfMyhOSn43jT$epi$V_C7?g_h=eUzyAGSJGXO1kw@&xDZ(YH9wtJa__HNDW2S0bkUqcp;DKd1SH-umO^K}y_>JX@b8iCO}MKw>pDpO%EE0Y#%{0h!S~pB~a}qZb&4w3lx-h?7Jummk=X+MsLf&_Y?##;c%MLVr> zXGXGWFmOZ5fZkQzXsBY>fCx~&mlp|D#N+`A0gIUzg!+&~e+nTP3uW69-cUyL#K^(# z=7U@)W>SG*O3cKd>GP5=BFTcuiC9P+v?Y=+9MWC835Aesu_OpV!(B0e9fB3v;yk9j z-OQ~*h&W>RSaB2ram{SH8wMh{y?YM81T8&yLd|#Klo&6ggo4BVCJ2I%8t=)*aM|6F zoy$DWfNW2La-1SwO6mc3`2X1i3Cgn$nLuxA zGA|#)K~{c|WB<|K{qH0_?cnhrIs1RI_y4J7=~fOw?w=Joe{c6#wr~Io`6sXaW5|Il z+@Phqp^!BrcK2!^{X-FA#O|)*hy^p4^7IA-?I%7l4-22Z>Yv)TwGfnSYwT;AaxlO` zw#cQRMMx6^p^AbLp(w}<2Ypcq|L$W~o;!dR1gN=#amkl7_Myd)2lXNOA&`mhw?v^9 z<3R$q55_1CD3wcwI3M&Sb3iio)4OCW1(A?yD1?2e?zb3)DC*iDEOaoJk_$o*rKUt- z;cp@ZoyXl3KEI;Abgcse2yg&=-n%X$M>+)CGow;;qY`}C?W7N3@1V7+9JPsuL>FA!Px&&pH#2hv0q!Q;o%(Q&NtYzgcS4kdCV zaVA6X1>gyczy=5+w6|~Hc8V)#o2C}gbciZ^{gp;^pG>J37!HmqH2dv?vot~RfJ`|{ zQ^fdl!I@1ZBqhmjdL*O-g(akfM3BgnqEeEQC!{5%PM{WUzk}K)Cb7le%-q3x0vbPtvAw` zZo2AvMJk#rG1;}IVAzQ30UZztSl`gJgrg|SNorAT=K@keHymOQUoM*sUX0W6Og8Bfs4s7^< z4D-3)3wQSd2X8M2z0J*UA7p!fh_I*#wwb~94hq(?Dj`SHLPe-&0x#)WKEVX}z>*c{ zU;y>UVN-YjBB;O~6)2_#hSUl$Ls(@t>kljN!x{XTOuvKzSE;}*0L_7-%P;P^QSEHT z-rO)(GJPGuxd#9X7vs=%7_&GVCkrhrODvPS_NNs>T%aD%)1n4^YN;0hp`2!ILl%HG z=sSZw4@iK%Pc$-udqC|7_%Xo>Sj}NmEKukLyYz&QqM(Hpd}4*QFaSg?Xz>A4oWKS~ z7!(3QPpJu6{9p+X+IYZe2U>y`XgLPbs6cMxEd$z?I!Tt6Kw~h~TL*p|gMq7eXzH)P zfDu&-HE5)Vx){MEP-6g%)L_J!Wu=afT`Qschf4q-WC*4yx(*hbHcdW2H--2CSiccS zZgd1XH33$-$0yIzXh$*x3Fy#i9s)BWRBC(QKobX(jKLUa8DePp%>dq0xAahfcoXoX zik83+Y?whP3y5a}zy#F8fTueMq6TnD@6Q+GQzsTT^*=Iux>XhjPW6L?t7t;#cNo~? zy#QJcgO(g2&`1lKU&6uUArPuX)e=YpLeW&<6O3@1ov=|!)#&=Fu9&L#B@9HtKq&Ox zhTsZ-m210dwiiL5XvXkpp)%q~giO23sqnhovsvlZ0@pGPazH5Gr|{w4RhWPFdIZNa zGaik&or^XHuunk({@-i<%oaI;{Y^wmQANOTT(}S626#l zv#@iV2%aZNx$fZU!`I#^dTlY%Btr{RdBeR` zU^MuCBbNYYwPB09x;a*QV^;LL>_>#p=PRO983mZ?Z$H@qBJN}0^zoF`T3H64vRv?x ziU#$_FlOe7J?w}6L*~X%@YQGRI~k{78$Qo4&rt`{hIcBYO>eKkA8_MZxP}V{B_HL} zir9sz9(zXXcIEx4GM6t4KR!=>CWwtZm*@%IW~*CU@eWcm-JZ(0ev=_NJ$mwndM1a^ zdd7+`mfz{uHd@ktZ;+R+}lw@no{Oajm&du67&wH1y zFgsd+N$`}0EaH!3U6k>y2+#Ojb$jvYM}hoKLk;+)Aib6REdgoen~^{yuJyWfw*PWq zh_FP{6BZKT<;cRI@5LIA$=c=TjnVjFXr$e`% zs%#vu?)ob4zbJNm`3Oi($E#9*yU5hzUV2^b^wg&r^TCuLp-`Q7a(_gXCyE_EV8m4` z_|7ac(*TjgKfT2tUtWj(~@ zNqR9C+xGC7L-~o~<8`gMGFQgp)$!bZ+m_vI*zYE&n$zRi$A)b2bu`zn2EED)APnVZ z0#;KV`dh+*AHJyeb!DvVPQ0D{d8P7bpXK=Lt4SafS}7;HCC#)~NZ!z^Ka$R3fg;uY z!OXALuN~jE7ut!^>$y9+Z5^sj!-v2B~v`z6UU;YuE-75_xYg9Qov7IPPIv|_t+ zmou|+(95K&{1gp5VE%f(bI3PFds&>e3@`7?Zyu$Ee2cB0%npA|yB%cIG*QC}w|j8? zrnS`TD4#e|BEe0jarImwcJv40Y-y!#>YmO>XX#wI^t9n5@@z9KIfay?e*aM1=Z?u) z){ZH{m#J$ghu^a^;lT?hj8nXXi=~g&8!t0;mdt5`i3c^QRxj^H|0X=6HmkW*ao9a= z{)IZ}T3V{vXlR=&Tli7M)u-;WTsbm;#xvUTi($jv8&3_nvuqfa*A0!vK<44QN#EyO z8yBo`S^#0!Djf8k`Qz!#X>MezV*Pl?$2{)-)EaW;$&h4ww$Kpi-XoD!yneKB>Zp_& z0VdaQ-y3^AC6FR}yq5g+^@&@Jy<6K24^>X0cU#o_$H@VxoDF)g{ct{>toQ?GcuHea zlWS_>l4S7}>ZjcwH>yJa@~dBhSGCCvZwQFpCogrIH%5Tzbl}sq`3(qyh-VXg9f;#@{XCgHs zrB!S9$$SN$`XeU3sf8cLLqBecz!wU)BUO{$4C@5%CDlpgEFQi>2M@2Q(=_~|Gx$pO zOPK+oHJ45 zEClnB^lJSaIGa5m;rpCZcmA|^!FwnoxaaZPDc)asy0^U4^zmKfV97DT`AxCffv^5x zDY_=Y*YUgYc3b*K0MDDCdU|(oaP#8kRjv>nRLNb1l16J*T(`@z+=r)}(j^i0FpQ#SLx}sm|YIl-YC>(kRue$W-w#cq`JJL-slKPV0%Xc~`tNG<@ z9~hDW@F&`o5m@U4^iFHc#g(=jk3B zjBm|-10r`wFYhxf*e35TzEV!ok%=nb9wqw9Et(EBn3AP0G5K1f>AF4s`RlvR z8}c>Jj&RT$VJFP!6z;6#Sb6#)PrSRSkc4NXi(Kx0aj}*7v1GSc`u_X78&6VqM!*pM zPt&2c;NcT%KkO$UTc;EBk2WPCOuROO$7aLar#DAm?ygrxJUnLl)k?TKggP`vMKuxF zM0mI7lu+{zwFWH*H}qXhHbn7FbNymg4$2Q?BbYq%EIpIn0UWaDRb%fraB;HD8~Ur+ zCYT?2=Vn}Bt+%Y7)Z}O7Tkze5uXr&eF4aIYE_yG)tV`zQ>A1s_3XtEJ+}lAGO1SKv zeH8k`^@_rUa3buh$J@&lDyzahtxJH!IwLYPVC^{e(BCB-)n$)N+`Tf;VfbgpZ_c#U z1BBkJ5%~4&aN$mC{~Sti_%pKZq_mTEfBNvI5Lwb=&UahNmec;BGhOV2fBw8GW6b*w zvicS$lXp$u>cY_@`dZ&lrPB%YW|%ai=Z|lbDdcegEsVESQEAyAIQ^5j=!{BPt9x}nebimK-Z(_xnfu6jOsx>!6t6lBp-j@gP2 zN4`Gno?j!Nle`dnv2VAVj~#cbSwB&??5O-lr{Kn4K@Huff7Xp$-09veD2W+CeapgSgf3Extxq5m;!$2u2@mTS!)`}C&k_Tx+vv)yS4jxF| z!r95dTY-AxWE+b9ftqd39#OjWXBS<-a4)3&Wj5QT)wa=3i^bI1_w|nD zRc2BO4I^2`M>p{&Ll&kvfO|GcKtFVlKB>yKdi#-*(C{m=_s_?R55D+K%1f)fTSYl+ zf703e9I^A~uTzjlNfEy2Px0A4m#)0NX?$zrPfv_-(^%Zd_4chJLYZi}-hOgqkr}rc zSi`UAR-ENDts)%>piW>C7tS@EuBuc!nIAaeOFkA>yHl=mAy^kA-y{jtD(#A1c+u6o z11+>Zux43bUmwL2m{b&yX|Z)ym0#?3?{A$X{fEFfAFrBdbMoZCJe(;h*o5&A{@eV+ zm1pAy0y9R(W{gtu?guw3*6ccuY&*9hxDwy?l4*H#^Jp|ObnJDt;UB6@-JT6ha|baf z)f+bdOnS?p`~Yq8BB&HLgrARponxml}kR+hX+e<+Zg1pqI@Y zE@l$M66eA=e)vtHMbMdvt8YEibFN0X_d2k(1qZ)C-BOBZe;VdgE(8#X>#EszJ+d8+ z6`FqI@Ly;26F1#&Zl%u3VmZ_G)~9AFxX5Xg(JzyNtE`05K#&6od zC1y4@1A_AKug3oRvvyl_-g%yvl)fn&8YLFVS19PK0z^!EPOMim`y`DRL&SMTBJ0Yy zgJ3eB!*}H{;?I-8>fIkt)dexq2Cf{jSJn()uhWdY`iGYPO)5)}cS|)Bli8_a*UA3C z*BLwG0^^&Q%GFz3U5k0$Q~=7T;;mSBs#FJ0|PoPfGJbFe>GD;H`IIbrv zuwlYAw_cWc@Hc!KZp?qaJ5WPSm8TVGad8Rg%LAoAmz0Dg3MDNiDIp~#C3X_}%z%RK zeG;-#AwVTn^V?CjTEEg8#<$*dZ5bTVQ8@Kjp~15m`&95uyCgPnZPPvzNQIL&td4|z zo?N3}b%B;e9dk9(*u2>U#Aj@vq!HHZBOOv< z64j*>rM_iW&pRsaiNZv}!?vtgo442yt73$*=&_nDM0r-9B!6+$dxPQaHdL6b^lQ4< zzcv_-!xX~j+V=uM_AIIuapAA{> zW&G8gtotI~^u*MH;9qI*J4c&*UK)&lJ|E^Z6Bp-5-g{1r|4YUcNO{g{-4x577dsJh z`4E*ADpN^7p+RJ{tVFtU@Y;ROb322)kA+xfIB8?SS>N@omJ&(T(}92LfGM+OjAeFO z|A*DKO;Xlxo$$U&i^&4{Pm0ACVLKjzEbh zAmZD8UHYi=UTfg6B=oAwIV=$DIgv2Y)yZ}!#_xLjSKZw^CT|xPGzAYCd-lH@6wX@T zTB=E3zEu{TBXA|V$74sWW+$Xa$;xAKPvEi1r1_dJkD3Uy()MDj_u)UB5!hAe1%}sV z{j_O>#KH>1aYh9BtxF6#ML_+2*^TnRuo;=Of5YY|~@>aIl{p?^C?1%e79rd(+%{TaN z_byn-=H%G5p0TNGm=JN8MGN$&FyjjF^PjwMFpbri= z`*k(G{*?p51jt?72@BqG-Pm*XynkNc$M`?CV$!3poOP)|8fdDTaRMn{m0m`r<^le( z$Sd6((76bA*3j^&>yh2pDJ#3gh`sN7A7AaZY9T)#XGA#Fs4~(!|7o>;mqftb8h>PN z|0ve^Sg}~sT{(j$mX=_*o9o;9-ORvFXG*vYhdk*t`{MuIaby!8l+1V zuph_B8&y{wztIFl@16LSEV@G!tAA%Bmd``J>eJlLoTRl=BCuW{9rE#g-PcEcsV6Oj zT|lN|tJX9X@VeP~Lzv9p!Z-tP&bMY`ZP3z*re@u70yEAl?7M!3_bx6#X(ytW8j@}ERY_e=r>*Y*fbk3^k_)2q_}%WrqI z_l2HHad_apunL)!2IjcMqN^vaCvkPDIm6)L{V$(~{=TT(%2LS|ce^Bd{b81i$VN() zRutSoU1`n=CDGK~|4G)D7MAHqN+s6_cCAdF-lVf(n4$T~)B9+7yt$=-xD3}vfa*&4puWLuOs7SwB~6QJn<16 zit0aaU5-FNR&8GU&SPHnVGy61ub58Eq~nW6#whRU!nuD_Ztb$|%J z#mV}x&z~2(|9Exgob&wfgHXJ@jls-0HSWyD&Zp6ODhb=sn5e{0p}v1nny`PWT&T=j zY1NqVSbuqJccOe=xHdt)R(VfiJR(1H9(1eMq|(@b{Ce-rbLXRkvh(hf&C%EHxIf(6 z`r_ef`sF3g;@nCDC&yRL3kZvO%bP|U_4cPVZ*s1ip3_N~e5k%b0 zyswhnDr$Z{2|4t8x)}{Mq>n0(RM~#|{S`5Dx$acW3$d-$sfd|f({p&YB%=OoZ{!~F gkC%sQBF~l~uZ+IPF4h3>eALWMN_PADj4z6DLSEk7y0Zmd>0x6RVo^ z^mLLPLzE(z<+v=yV!9tXYXqF@U6q_0ljY|#L4nVgY-FKi+0?82@N-)4gsspfD zj!TSY4xlC&a0d{b2HwAaPgQj=fH&SOwMD_%@8b_tW&9ji%ORZVj$eI^(;k8$FuTr@ zkP^Hgwdpus`N5qAKtcNU{bvRRC2q0|e{kF$8A zsuSQ;4#FTd-5o$JK(+&>muiFQ|43}QIsle47?IfI0FtX?WI!m3(cA&sr<+mifT58H z$;s!$>LD13pc=6wSBGQ=fI!9MD|l-{q8tDMTFPSB>t6!k+TB-_r_xa{>;VAId}W05 S-x{R=0000nBwn9J$=>&3iNRcK1$* zE;JOU#=TC)?$HO#C3>wzWG9C`9Jb_C?1(-<;=2AR3U?0?!2rZZg{*(RUaW}9{R=zR z6gy%&kRp#JQvUyD{go9F7BkQS+`s?{Q#&O2%4WHB?n>S!z(#~xdXP)tn(7DJYPJcm z5rK?B-uU>Ar&htmPpomcK#N;xpDed=DdPQ}I6cU?Vr$psmO096TyP_sYTxpgK7NDt_sJTV`Q|C-!d0Njn<>moo*k+1Gf3)>aaN&o=k zq3pT{o&4O^=Ou=X)7)V?mZGu_Tw*q!3Ct zR??;Is;E6an_ox(j+}xn2%y@5m=pp6kUi)2Fv#ppA`lxK>bTIC(wVi zrSY}gbz|W`Rh8VXA)-1v;r++gk#+1&f0}ji1!`lT=Y>Ma%m4rY07*qoM6N<$f(mgE AQ~&?~ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Interface/Actions/actions_ai.rsi/door_overcharge_on.png b/Resources/Textures/Interface/Actions/actions_ai.rsi/door_overcharge_on.png new file mode 100644 index 0000000000000000000000000000000000000000..ea654d8634b7be6024065ec69cc939a230589dd8 GIT binary patch literal 495 zcmVq3o(U;s4rk=ULbh}gD+rhV<}k1!oo78 zLaZ&cj?a)6P&-kuQ-X>hcBkLLT;}#>e`XDck`I=<+ufV*`(|z@F=mdxjBa}^!}vAw z>x=Dt{6s`8mHh0mYnE18`SZu?#Oxl8&G_b79j~4u03h<6{ZVnB0<{2gPviv5rIaEm z18@xTx6fK>E(Iz9+&##b7c+A{=oRZJSx{$y+`HDah!zlXPtayTl>wi7zDI*70kQ5O z4g+hkSy+fwI(1*|H9RZ)WXwc>?Vhe7QoQrs9kWn(jLLviS57)Q*~+iIy({lK61?ho z&*#B8DS_7ce9Uh|Fax#|o0yY_-j(1y1-$k|%*iEENnEHec#omW0m!AgYhri>K=H8O zDW0=zYJd~+d&xav*mq|^6o4Flj26Orf&KHH`NrhBADW*B7PQ9 zH?<9f`q|V5Q_(K8&`4`U{07tLrsBd6qDDvrAqqyjDfF|kv4R_IXiZwEZp_&G@WtuO zeQz?UpeH`x``fWpL9uN5jq`PtDrJa-deYn7^=z5h z$zt2|290G!215)u7-#}q+ThdQ=GZc`lf|~_4G@&!e0rK)dGO4SKNZJ&POi1hC$=Io zL`2g+p?hdTaXOu~&fKynIw zq?vOFM~AA!{h3)-=Cu{;NT1J>pIG^KEiX0AoWoE74yqCh#f4QXibXE$H!I`_!#SWu zq-Zq@z=44u^^dbIrxyOEC&w5v2rIzR&=-QJ*A3cAAkmBY%pyA~bM%e)eA4))$0v@U z-|vUGMg%7~&{@Uqsmzhww?K}gxFi8w1dib0l_dru1l6oKie}__3(!J89a@+*oFxI} zyN?Rz{Y2_D=tUs;HTzc5ekyWD$U`}pG^63LmMIy+}(mI!Vq${v! z@7~2uP_tP$1(SyCIj{;}x*i+$D{5(A?CpR}EoThmNT@$2*7WW- z_)m_E3S&zJOnjZm-ERrE8OSd|1G`x&QIP)NUlapZPEY8{Nq<&lVuhYDHftzI=jvij0vg3 z2Uv);d}*H#m>pfTj)0%gx>b5}7`R8$bm1w@tKAV}vaUQkoXXpl&=C~Yz)d4?WKVi6k`3j2I zvd$8Q|Ns7>h(%ZS5#<1oXIfrA`Tz0sZVX2dl?|7+7crP8)nE}X20Egbpni1E5bc0F zFW)h!hzr5_j6nDANVj9?xdY*!oYz9o@~Hy4VA{!%fg$8Hi4NG6Y0s##?lL?vf-HBR zafqO$$RPW}WiY*Te-V(}O_~Fc!Ojeb<;bCMl8AIlCGkv zX8D>qeGCS^2}C&r1}F5xpvhF_KRwN6L|5P@z|64g!(WEF({~ur6~lmq zg#}heo;Yy=ryg8pGomYi0d$4Pmd>0x6RRcZ>FHP+c%|e3oN%04_)P&smG%J7hiRp|mk2n4sk#z=X{KAcY_e zFaRs2QI>0Ll1B6mCv1&+mfTgx5 zIAMMK!N?FH#E0R#?cY9v*`8ed7;-D#ePZC}fD|3aufE1<4+|j|&aShBv)A=pgIffl z`H|QN%Y#a^7=obu)TZNj&BvPt&;iI`^fZCZa#8?Z2Y`b9?fcIRyn_GWIKEW_#SzGs zgXECag7kvSAlm`-03cKk?Eq|+gR&tAQ{o7s z9DvPo`(#-#8k?xpwyzBO$X<07&5pSM~q2=p7MlHod!M aqW}PyZhV8E5WCI*0000 Date: Tue, 3 Sep 2024 16:01:38 +0300 Subject: [PATCH 2/8] feat: now when research is unlocked in console, approver of reasearch is radio-ed too (#31170) * feat: now when research is unlocked in console, approver of reasearch is radio-ed too * refactor: now most of events that require actor name to be radio-ed or logged use TryGetIdentityShortInfoEvent which is subscibed by id-card system and borg system (to work for both carbon and synthetic life-forms) * refactor: moved TryGetIdentityShortInfoEvent on id card system to shared, fixed cargo cent-com-originated orders * remove unused check * refactor: decoupled systems from IdCardSystem (those that are not dependent on it anymore) * refactor: removed unuseed usings * feat: emagged cargo/research consoles wont radio messages on buy/research confirm anymore --------- Co-authored-by: pa.pecherskij --- .../Access/Systems/AccessReaderSystem.cs | 28 ++++++++++++++++++- .../Access/Systems/SharedIdCardSystem.cs | 2 +- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Content.Shared/Access/Systems/AccessReaderSystem.cs b/Content.Shared/Access/Systems/AccessReaderSystem.cs index dd0bf7bde2..94c840a975 100644 --- a/Content.Shared/Access/Systems/AccessReaderSystem.cs +++ b/Content.Shared/Access/Systems/AccessReaderSystem.cs @@ -386,7 +386,33 @@ private bool FindStationRecordKeyItem(EntityUid uid, [NotNullWhen(true)] out Sta /// The accessor to log private void LogAccess(Entity ent, EntityUid accessor) { - if (IsPaused(ent)) + if (IsPaused(ent) || ent.Comp.LoggingDisabled) + return; + + string? name = null; + if (TryComp(accessor, out var nameIdentifier)) + name = nameIdentifier.FullIdentifier; + + // TODO pass the ID card on IsAllowed() instead of using this expensive method + // Set name if the accessor has a card and that card has a name and allows itself to be recorded + var getIdentityShortInfoEvent = new TryGetIdentityShortInfoEvent(ent, accessor, true); + RaiseLocalEvent(getIdentityShortInfoEvent); + if (getIdentityShortInfoEvent.Title != null) + { + name = getIdentityShortInfoEvent.Title; + } + + LogAccess(ent, name ?? Loc.GetString("access-reader-unknown-id")); + } + + /// + /// Logs an access with a predetermined name + /// + /// The reader to log the access on + /// The name to log as + public void LogAccess(Entity ent, string name) + { + if (IsPaused(ent) || ent.Comp.LoggingDisabled) return; if (ent.Comp.AccessLog.Count >= ent.Comp.AccessLogLimit) diff --git a/Content.Shared/Access/Systems/SharedIdCardSystem.cs b/Content.Shared/Access/Systems/SharedIdCardSystem.cs index c031902b6e..7a79070bd8 100644 --- a/Content.Shared/Access/Systems/SharedIdCardSystem.cs +++ b/Content.Shared/Access/Systems/SharedIdCardSystem.cs @@ -239,7 +239,7 @@ private void UpdateEntityName(EntityUid uid, IdCardComponent? id = null) private static string ExtractFullTitle(IdCardComponent idCardComponent) { - return $"{idCardComponent.FullName} ({CultureInfo.CurrentCulture.TextInfo.ToTitleCase(idCardComponent.LocalizedJobTitle ?? string.Empty)})" + return $"{idCardComponent.FullName} ({CultureInfo.CurrentCulture.TextInfo.ToTitleCase(idCardComponent.JobTitle ?? string.Empty)})" .Trim(); } } From c4d14da07c00487cda53f5a34918e8acd7513856 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Sat, 11 Jan 2025 10:04:13 -0500 Subject: [PATCH 3/8] Update SharedStationAiSystem.Held.cs --- .../Silicons/StationAi/SharedStationAiSystem.Held.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs index 5c43b643b1..e89c7e90bf 100644 --- a/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs +++ b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs @@ -1,11 +1,12 @@ -using System.Diagnostics.CodeAnalysis; using Content.Shared.Actions.Events; +using Content.Shared.IdentityManagement; using Content.Shared.Interaction.Events; using Content.Shared.Popups; using Content.Shared.Verbs; using Robust.Shared.Serialization; using Robust.Shared.Utility; + namespace Content.Shared.Silicons.StationAi; public abstract partial class SharedStationAiSystem From d7317a7d34966b078ee0cb45599175f94b5127cb Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Sat, 11 Jan 2025 10:04:20 -0500 Subject: [PATCH 4/8] Update SharedStationAiSystem.Held.cs --- Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs index e89c7e90bf..33afb5673f 100644 --- a/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs +++ b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs @@ -6,7 +6,6 @@ using Robust.Shared.Serialization; using Robust.Shared.Utility; - namespace Content.Shared.Silicons.StationAi; public abstract partial class SharedStationAiSystem From f293d7e519ff55993729f3de46c978df54d1faa3 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Sat, 22 Jun 2024 15:12:58 +0000 Subject: [PATCH 5/8] add access reader log wire (#29094) * add LoggingDisabled to AccessReader * add LogWireAction * -m give everything besides high-security door a log wire * make LogAccess public and support string arg * add log when pulsing * m * l --------- Co-authored-by: deltanedas <@deltanedas:kde.org> --- Content.Server/Access/LogWireAction.cs | 74 +++++++++++++++++++ .../Components/AccessReaderComponent.cs | 7 ++ .../Access/Systems/AccessReaderSystem.cs | 20 ++++- Resources/Locale/en-US/wires/log-wire.ftl | 1 + Resources/Locale/en-US/wires/wire-names.ftl | 1 + Resources/Prototypes/Wires/layouts.yml | 4 + 6 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 Content.Server/Access/LogWireAction.cs create mode 100644 Resources/Locale/en-US/wires/log-wire.ftl diff --git a/Content.Server/Access/LogWireAction.cs b/Content.Server/Access/LogWireAction.cs new file mode 100644 index 0000000000..1e97d5c9d6 --- /dev/null +++ b/Content.Server/Access/LogWireAction.cs @@ -0,0 +1,74 @@ +using Content.Server.Wires; +using Content.Shared.Access; +using Content.Shared.Access.Components; +using Content.Shared.Access.Systems; +using Content.Shared.Emag.Components; +using Content.Shared.Wires; + +namespace Content.Server.Access; + +public sealed partial class LogWireAction : ComponentWireAction +{ + public override Color Color { get; set; } = Color.Blue; + public override string Name { get; set; } = "wire-name-log"; + + [DataField] + public int PulseTimeout = 30; + + [DataField] + public LocId PulseLog = "log-wire-pulse-access-log"; + + private AccessReaderSystem _access = default!; + + public override StatusLightState? GetLightState(Wire wire, AccessReaderComponent comp) + { + return comp.LoggingDisabled ? StatusLightState.Off : StatusLightState.On; + } + + public override object StatusKey => AccessWireActionKey.Status; + + public override void Initialize() + { + base.Initialize(); + + _access = EntityManager.System(); + } + + public override bool Cut(EntityUid user, Wire wire, AccessReaderComponent comp) + { + WiresSystem.TryCancelWireAction(wire.Owner, PulseTimeoutKey.Key); + comp.LoggingDisabled = true; + EntityManager.Dirty(wire.Owner, comp); + return true; + } + + public override bool Mend(EntityUid user, Wire wire, AccessReaderComponent comp) + { + comp.LoggingDisabled = false; + return true; + } + + public override void Pulse(EntityUid user, Wire wire, AccessReaderComponent comp) + { + _access.LogAccess((wire.Owner, comp), Loc.GetString(PulseLog)); + comp.LoggingDisabled = true; + WiresSystem.StartWireAction(wire.Owner, PulseTimeout, PulseTimeoutKey.Key, new TimedWireEvent(AwaitPulseCancel, wire)); + } + + public override void Update(Wire wire) + { + if (!IsPowered(wire.Owner)) + WiresSystem.TryCancelWireAction(wire.Owner, PulseTimeoutKey.Key); + } + + private void AwaitPulseCancel(Wire wire) + { + if (!wire.IsCut && EntityManager.TryGetComponent(wire.Owner, out var comp)) + comp.LoggingDisabled = false; + } + + private enum PulseTimeoutKey : byte + { + Key + } +} diff --git a/Content.Shared/Access/Components/AccessReaderComponent.cs b/Content.Shared/Access/Components/AccessReaderComponent.cs index cbd3f5acd6..903ceab186 100644 --- a/Content.Shared/Access/Components/AccessReaderComponent.cs +++ b/Content.Shared/Access/Components/AccessReaderComponent.cs @@ -65,6 +65,13 @@ public sealed partial class AccessReaderComponent : Component [DataField, ViewVariables(VVAccess.ReadWrite)] public int AccessLogLimit = 20; + /// + /// If true logging on successful access uses will be disabled. + /// Can be set by LOG wire. + /// + [DataField] + public bool LoggingDisabled; + /// /// Whether or not emag interactions have an effect on this. /// diff --git a/Content.Shared/Access/Systems/AccessReaderSystem.cs b/Content.Shared/Access/Systems/AccessReaderSystem.cs index 94c840a975..d003aeea95 100644 --- a/Content.Shared/Access/Systems/AccessReaderSystem.cs +++ b/Content.Shared/Access/Systems/AccessReaderSystem.cs @@ -380,11 +380,11 @@ private bool FindStationRecordKeyItem(EntityUid uid, [NotNullWhen(true)] out Sta } /// - /// Logs an access + /// Logs an access for a specific entity. /// /// The reader to log the access on /// The accessor to log - private void LogAccess(Entity ent, EntityUid accessor) + public void LogAccess(Entity ent, EntityUid accessor) { if (IsPaused(ent) || ent.Comp.LoggingDisabled) return; @@ -428,7 +428,21 @@ public void LogAccess(Entity ent, string name) name = getIdentityShortInfoEvent.Title; } - name ??= Loc.GetString("access-reader-unknown-id"); + LogAccess(ent, name ?? Loc.GetString("access-reader-unknown-id")); + } + + /// + /// Logs an access with a predetermined name + /// + /// The reader to log the access on + /// The name to log as + public void LogAccess(Entity ent, string name) + { + if (IsPaused(ent) || ent.Comp.LoggingDisabled) + return; + + if (ent.Comp.AccessLog.Count >= ent.Comp.AccessLogLimit) + ent.Comp.AccessLog.Dequeue(); var stationTime = _gameTiming.CurTime.Subtract(_gameTicker.RoundStartTimeSpan); ent.Comp.AccessLog.Enqueue(new AccessRecord(stationTime, name)); diff --git a/Resources/Locale/en-US/wires/log-wire.ftl b/Resources/Locale/en-US/wires/log-wire.ftl new file mode 100644 index 0000000000..735816a52d --- /dev/null +++ b/Resources/Locale/en-US/wires/log-wire.ftl @@ -0,0 +1 @@ +log-wire-pulse-access-log = ERROR: Electromagnetic spike detected diff --git a/Resources/Locale/en-US/wires/wire-names.ftl b/Resources/Locale/en-US/wires/wire-names.ftl index 851241f85c..a1ebec9e7d 100644 --- a/Resources/Locale/en-US/wires/wire-names.ftl +++ b/Resources/Locale/en-US/wires/wire-names.ftl @@ -66,3 +66,4 @@ wire-name-bomb-boom = BOOM wire-name-bomb-bolt = BOLT wire-name-speech = SPKR wire-name-listen = MIC +wire-name-log = LOG diff --git a/Resources/Prototypes/Wires/layouts.yml b/Resources/Prototypes/Wires/layouts.yml index 20d5d33603..7ef30d116b 100644 --- a/Resources/Prototypes/Wires/layouts.yml +++ b/Resources/Prototypes/Wires/layouts.yml @@ -5,6 +5,7 @@ - !type:PowerWireAction - !type:PowerWireAction pulseTimeout: 15 + - !type:LogWireAction - !type:DoorBoltWireAction - !type:DoorBoltLightWireAction - !type:DoorTimingWireAction @@ -60,6 +61,7 @@ wires: - !type:PowerWireAction - !type:AccessWireAction + - !type:LogWireAction - !type:VendingMachineContrabandWireAction - !type:VendingMachineEjectItemWireAction - !type:SpeechWireAction @@ -69,6 +71,7 @@ wires: - !type:PowerWireAction - !type:AccessWireAction + - !type:LogWireAction - !type:AirAlarmPanicWire - !type:AtmosMonitorDeviceNetWire @@ -125,6 +128,7 @@ - !type:PowerWireAction - !type:PowerWireAction pulseTimeout: 15 + - !type:LogWireAction - !type:DoorBoltWireAction - !type:DoorBoltLightWireAction - !type:DoorTimingWireAction From 17094279ba7cbc6d7738dd9dbc4d816448b96647 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Sat, 11 Jan 2025 10:12:35 -0500 Subject: [PATCH 6/8] Update AccessReaderSystem.cs --- .../Access/Systems/AccessReaderSystem.cs | 27 +------------------ 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/Content.Shared/Access/Systems/AccessReaderSystem.cs b/Content.Shared/Access/Systems/AccessReaderSystem.cs index d003aeea95..181af53893 100644 --- a/Content.Shared/Access/Systems/AccessReaderSystem.cs +++ b/Content.Shared/Access/Systems/AccessReaderSystem.cs @@ -6,6 +6,7 @@ using Content.Shared.Emag.Systems; using Content.Shared.Hands.EntitySystems; using Content.Shared.Inventory; +using Content.Shared.NameIdentifier; using Content.Shared.PDA; using Content.Shared.StationRecords; using Robust.Shared.Containers; @@ -405,32 +406,6 @@ public void LogAccess(Entity ent, EntityUid accessor) LogAccess(ent, name ?? Loc.GetString("access-reader-unknown-id")); } - /// - /// Logs an access with a predetermined name - /// - /// The reader to log the access on - /// The name to log as - public void LogAccess(Entity ent, string name) - { - if (IsPaused(ent) || ent.Comp.LoggingDisabled) - return; - - if (ent.Comp.AccessLog.Count >= ent.Comp.AccessLogLimit) - ent.Comp.AccessLog.Dequeue(); - - string? name = null; - // TODO pass the ID card on IsAllowed() instead of using this expensive method - // Set name if the accessor has a card and that card has a name and allows itself to be recorded - var getIdentityShortInfoEvent = new TryGetIdentityShortInfoEvent(ent, accessor, true); - RaiseLocalEvent(getIdentityShortInfoEvent); - if (getIdentityShortInfoEvent.Title != null) - { - name = getIdentityShortInfoEvent.Title; - } - - LogAccess(ent, name ?? Loc.GetString("access-reader-unknown-id")); - } - /// /// Logs an access with a predetermined name /// From 0f7a66278f1a013a3a51212f6a4c7bd4f96656a6 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Sat, 11 Jan 2025 10:17:53 -0500 Subject: [PATCH 7/8] wheeee --- .../Actions/actions_ai.rsi/ai_core.png | Bin 269 -> 524 bytes .../Actions/actions_ai.rsi/camera_light.png | Bin 309 -> 572 bytes .../Actions/actions_ai.rsi/comms_console.png | Bin 0 -> 419 bytes .../Actions/actions_ai.rsi/crew_monitor.png | Bin 295 -> 575 bytes .../Actions/actions_ai.rsi/mass_scanner.png | Bin 0 -> 909 bytes .../Interface/Actions/actions_ai.rsi/meta.json | 3 --- .../Actions/actions_ai.rsi/state_laws.png | Bin 241 -> 315 bytes .../Actions/actions_ai.rsi/station_records.png | Bin 0 -> 465 bytes 8 files changed, 3 deletions(-) create mode 100644 Resources/Textures/Interface/Actions/actions_ai.rsi/comms_console.png create mode 100644 Resources/Textures/Interface/Actions/actions_ai.rsi/mass_scanner.png create mode 100644 Resources/Textures/Interface/Actions/actions_ai.rsi/station_records.png diff --git a/Resources/Textures/Interface/Actions/actions_ai.rsi/ai_core.png b/Resources/Textures/Interface/Actions/actions_ai.rsi/ai_core.png index 8dd3031f9fc0b41e613e0f27050665c312010aa9..89cc7aa1654fb532f1193e972a7c2ac68b068981 100644 GIT binary patch delta 510 zcmVe3CSE0LTuQBQP8Q z20S7(bpXSs=O|oE2Yh)$T?-4pLg;>OtkSd(0nP8I=F&X`u7Cf-Yc8e(Y-_1w@%iZx zn&c38dWwO8SBf&rKR-kGnB)+E0i8(lEWffGLc@GaatOdIzqN*eA$B5ZmM_kS=sn&` zg%J4ln}Ol}Khhk43@8c#7|>)wusZ^`ver#J+VHE#@p(9&k8@}L9@a+v=* zOua;g022c~0DlSrSSX-djx2_(4hBFz24RpVKp4hH1Na>P(+mS3A7f*qs{;X$k3ksb zI2a!d5SIovLixy{fXs%eqgfh&0c2kzI|5xD2v9u@AX|verXURv9|9oXgDge17#1QF zgaC1AKyw2myP-z`2!P80ENLM1A=Ghb{6 As{jB1 delta 253 zcmeBS>1CQAQP0B6z`)QLl71XWsRa0hxE?rgz}VOr$YbD>WRTKj@SetCkicMD#o%1e zka?M5g#bf6U)3ockT%AWAirP+hi5m^fSl=`E{-7@6O$7ZcqCXSHZTM@1aNY4FtN7u zOl(l{IKax;z}n;dkYSb5UKy@a3$%>VoE)V?T+5EF2~F6riFcLK=4x|^H#68mC*Ite z6&V$EZI$R{0j*0;&X)s1mbA6CEnMN@%ge32KuMR^*EJ$bqAuFtPUFKMgND^7X7C1X z6n+=ISHTuux71Op`kJvkT{6q!3*8Osi8fxP7D>gTe~DWM4fN<>hu diff --git a/Resources/Textures/Interface/Actions/actions_ai.rsi/camera_light.png b/Resources/Textures/Interface/Actions/actions_ai.rsi/camera_light.png index 041b9b9bf7c8b9cca92a5cb784ab672663a101cf..53ebb32c59fa148cbbc8dfe53367c31b24b835be 100644 GIT binary patch delta 559 zcmV+~0?_@n0=xu}7=H)`0001UdV2H#000SaNLh0L01FZT01FZU(%pXi0005*Nkl#i>T1Sj3w!O_`K`~xl>{KBnJ1VybN zS`ie~oW9)VC3#6+jIo0rc)7{VOYS-6-6RC~>*&!BN~O~0Z+{f6)oPu(ogFFeoXoYj zQ^!Z5FTe~KnaY&_YY2%Dfi?FpQG!02rFCiTPYL?Q`@ z15`dd4ZOVr1N|!3AyZc2JC0a8FafVHNdN{SE;2Y0-vhzIkwj8BlIQ@fr=mCq;v7lo zMwkFW7j!jJAb*O;^R@rlI0PK%HBMUCQiDynxCuNo)L>x_7MA7|GMvZ39$IZgM=J*= z=YjKmb#unzlFHYQ!j9w5FzR7xhU3TWwP*7ceLJ0Fu9kHV_9yr9?qR%P%Jp$l`#mveopje@o6k`YsK> zi0DAtvHqeW3yOoLs4q*d4z#=9vHS8v*{%V6I_ySdz0one%1hoQ?7=Hu<0001iRAXEG zfB;ZHPzeN-!K9KPP(a892`GXDLPOJ1L!kgH;Nn(ZmV%-pqkp};EEQQrdPO@-4NOG^ zObu8d1*iff0#}h51`=sYgR97#u?#3uw#pj_zyewAozv1Q(v~8raB*=<&su^o10)re zg>VPVl`cn)!2ALN(V<5}Lysz=`1TB{ikO(tm>3ilK0ZEZDq_%7xSU3}W%pJzTfALR sRUkqPGt^O4Kp!GX2@z2kQAr2@03YXY!vx7`JpW{t{SN_>m{kUTBe#X8_Z{{yCdRd{QL=>ARCK`7x0K z`E>y&QMPNG2+R(T`KWGRoAwGsBQU}HIcw9NE^h)td6i>Nfyxt*KCoAgJ-Xh{fHMI? zH7=qPnEkNv%RizYfwg+ye;_)62+aY^_e)V80sg)o>cd3n-#^XXx&WCZveSOiLTCU0 N002ovPDHLkV1hKUxu*aC literal 0 HcmV?d00001 diff --git a/Resources/Textures/Interface/Actions/actions_ai.rsi/crew_monitor.png b/Resources/Textures/Interface/Actions/actions_ai.rsi/crew_monitor.png index 78fad17a76c58ceb3ff7bdc60107aaf01f477511..73abb66ac1fef4180937fb2aeb18867d714c5925 100644 GIT binary patch delta 562 zcmV-20?qxW0>1>17=H)`0001UdV2H#000SaNLh0L01FZT01FZU(%pXi0005;NklIsFco4yx=lurp7yJRew;xjP?UzWup=WP`^dLwNA}tEFUGv(V zc9Ko9O`G+i10|DWl6mtolWmCpx+JobWm*0kP6va*%I`{H=YMLlR_Dr(24depMs#vk zD**Ul5G4Q$Nl$A9Kp(GKw+vuB()+E6eWQot^4R6gT7Q1r2#=qEyO(8q)zEF8=1X9` z3k!&A<-G4^GME9=IgbH^Y1{Pd|ad_C+oPPluAhv}Q>0I{BJ-23nL6{7TMYcz;0x-a5E*&!%-<=Vq3Q+58Qxs=bq(tGGIGjneou2eaFZHp0CJ_@|OmYaDOzi#fD%5EsvuQomt|wavt`) z#==sW0Yt)Lp0BIrNSUn_QzOAxvF~ja0D0!9^>(p%5iJIN=kA$nv+`a6z?RJ%jTtFf zYy+!eyL$l9q>gcoEsI3I2W%3sNBn=qE_PUa4B-E|_AohAI~}O6UQ$$RJ|mhS zU?2<_1(ARNP(V-#2?zoOgp84ZB1pgm2`EBTgocJ18=IxURe!jKmzRdPxV6Dmn3k89 z2OFEUAykx>hlix4wWXyXtH|i+=tzdE2t`*Bie?77Eg0^=bg8kirLpm<#mFjVPI2*G zf~>;S*!VDt3Rf2&R5MJC52J>Ms}GtjriYDfkyUuKc69VUK~{0p7*z$(7Bn;PhB`(> eVMHY%006cpT@icIx{}ZU0000rj^o$pMiME|20vsDQZ>_}p0``kW++1K1SC!@EQSokSb(8AG~6^td0+Zs54u z1e{!O{9uphb+^yL3-)s&Imtj72;W&im?x@s5ta6d&LNRAC4rtf4>l$TP&OpdQxxd=@L?p{9uw#XUF34#kJTm^Q0vZ!DIc7F%Xi%dQjFKZ z^H@pL{tB2`Ek`16i~+8D+C?r+WuhNwx8psVDBv`P(!dD!61Bs=}X5>vXFwrXz z=>4xU@&Tu;SB3hoA(?djn(J1-3uON%fZVZs2AGj2--%w~dV5D4ZbE*10UEjJkDJzj zH_u=Bpa!0y)$XF#(p4XM0#83D=4Ou4I7w=)3nXIQm&W&hzAStld073~8fHN4d)2=V z)lVnQds?vi8n}cS&MGyWwS9z7=OEBgGvWkd&S>p?Lk!%6s6L$%<7q<;yHWo=Y;{t8 z>^!dD)E_b>mf9rROc}BaV_?RPt|PxW=q5%h+bY^LSXdbe?pNa`Yw1aNd5hv-l2qi{t7zvH7QFpRybtPMGpj#50bK)ZOEwj| zBkzOvLiBxJ>w8DhgN1luvlW%;u%dfjT9_817~uEy jqxxea?XUke`)|JiN$gOT>8$E700000NkvXXu0mjf3G1U` literal 0 HcmV?d00001 diff --git a/Resources/Textures/Interface/Actions/actions_ai.rsi/meta.json b/Resources/Textures/Interface/Actions/actions_ai.rsi/meta.json index 1efee13f3a..434b9052e0 100644 --- a/Resources/Textures/Interface/Actions/actions_ai.rsi/meta.json +++ b/Resources/Textures/Interface/Actions/actions_ai.rsi/meta.json @@ -28,9 +28,6 @@ { "name": "mass_scanner" }, - { - "name": "job_view" - }, { "name": "comms_console" }, diff --git a/Resources/Textures/Interface/Actions/actions_ai.rsi/state_laws.png b/Resources/Textures/Interface/Actions/actions_ai.rsi/state_laws.png index e30e891745fb526dd73b5f597eec1a457f4b1aaa..ff546e13b1fe9c117f99a23cd8c4491d9a14f3f3 100644 GIT binary patch delta 300 zcmV+{0n`5R0lNZ_7=H)`0001UdV2H#000SaNLh0L01FZT01FZU(%pXi0002(Nkle3CSE0LTuQBQP8Q z20S7(bpXSs=O|oE2Yh)$TL++l(Gb9N05>oZitEwFwwITP2!8>P<^Jnv=pARC5mFg`h|IRM#bFpH?@bHWb5W+)YXPS^pYrU5b? zG~j7~38xHt8lVxt?Ev(kr@I3{mQyLAk>>z9SPlZ1i4as?gNjUA0Fc=P9q<)cS=@V$ yAxtYU+8!7UfhEBe0-*Lfy*ef^FyLLYQ2+q!HD{@M{M6I{0000`ZfEhUx?OPofAH{g#bY_Qt#&I|W-00k1$GNZd8BA>IJ!^$lz#<-Z)@)h8BxV7 z-&X&NrAjJlOycvnd3+kWE^vS8n9Fc9{b1d+q^^^xT2d$ezdP~A|Gnc3o646PRwPbc YZDS!EF1PlfUkAw9p00i_>zopr0M6x81^@s6 diff --git a/Resources/Textures/Interface/Actions/actions_ai.rsi/station_records.png b/Resources/Textures/Interface/Actions/actions_ai.rsi/station_records.png new file mode 100644 index 0000000000000000000000000000000000000000..c1f1420445139a05276a5c6d1347a247bb43948b GIT binary patch literal 465 zcmV;?0WSWDP)T7sFevv*8xS_}sD40Be zC#1*=cmU1SdB7EEs4~pZLC%2gWZANX0jEf|k?fOBD_OSh0RB4e=%6TyeU6}2Rkd+j z1%o#aZyLObW0B}HW&jT(-J71~0Ly77l`t`oghSwf!BG9O)|UIc)tz2G+Rwhftf5O_ zvj$jf0bcHpV@XF_D$$0Mp*{>fXNG2_(dirp|J>Qq%u_!Ce+76}F`dpy5Nw1Vs0mw1 z2Tu>2)_&ZxCACrY0B5YNfLUwa12_*^D$t+=cNYxE`&AVL zru%GB(#$CgDLfCN6_~t=Y%SpFho_;zd%%8jk{{0z0;`#h09|*jj|b@$NX6AEa3#oh zK?r=mOZ(sF7bRfUwsdBh4cIn(9P(4&h8kezTymQL(kjr}!qJvXZbOk&feSK>L05ru zGK@ie8)m{~--Id1Rsm(N+^zyruY@XKzSnd8m>_=r*X$oZcVe-AVMRD`00000NkvXX Hu0mjf*G0xB literal 0 HcmV?d00001 From 0ce4d63b511c1892bb1f9b2847eaab6ad3bc7414 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Sat, 11 Jan 2025 10:48:57 -0500 Subject: [PATCH 8/8] Update silicon.yml --- .../Entities/Mobs/Player/silicon.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml index 6c169821ab..6685e47520 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml @@ -289,10 +289,29 @@ drawFov: false - type: Examiner - type: InputMover + - type: Speech + speechVerb: Robotic + speechSounds: Borg - type: Tag tags: - HideContextMenu - StationAi + - type: LanguageKnowledge + speaks: + - TauCetiBasic + - SolCommon + - Tradeband + - Freespeak + - Elyran + - RobotTalk + understands: + - TauCetiBasic + - SolCommon + - Tradeband + - Freespeak + - Elyran + - RobotTalk + - Sign # It's intentional that they don't "Speak" sign language. # Hologram projection that the AI's eye tracks. - type: entity