From 67253a3fe19e8da32c75cb416ecf1ef2b99555dc Mon Sep 17 00:00:00 2001 From: BombasterDS <115770678+BombasterDS@users.noreply.github.com> Date: Sun, 11 Aug 2024 19:04:42 +1000 Subject: [PATCH] Change suit sensors on other players (#29668) * Suit sensors can be turned off on other players * less doafter time + interaction (nostate) check * code cleanup * code cleanup 2 --- .../SuitSensors/SuitSensorComponent.cs | 20 ++++--- .../Medical/SuitSensors/SuitSensorSystem.cs | 60 ++++++++++++++++--- .../Medical/SuitSensor/SharedSuitSensor.cs | 14 +++++ 3 files changed, 78 insertions(+), 16 deletions(-) diff --git a/Content.Server/Medical/SuitSensors/SuitSensorComponent.cs b/Content.Server/Medical/SuitSensors/SuitSensorComponent.cs index 9079655c80..91039712e5 100644 --- a/Content.Server/Medical/SuitSensors/SuitSensorComponent.cs +++ b/Content.Server/Medical/SuitSensors/SuitSensorComponent.cs @@ -14,37 +14,43 @@ public sealed partial class SuitSensorComponent : Component /// /// Choose a random sensor mode when item is spawned. /// - [DataField("randomMode")] + [DataField] public bool RandomMode = true; /// /// If true user can't change suit sensor mode /// - [DataField("controlsLocked")] + [DataField] public bool ControlsLocked = false; + /// + /// How much time it takes to change another player's sensors + /// + [DataField] + public float SensorsTime = 1.75f; + /// /// Current sensor mode. Can be switched by user verbs. /// - [DataField("mode")] + [DataField] public SuitSensorMode Mode = SuitSensorMode.SensorOff; /// /// Activate sensor if user wear it in this slot. /// - [DataField("activationSlot")] + [DataField] public string ActivationSlot = "jumpsuit"; /// /// Activate sensor if user has this in a sensor-compatible container. /// - [DataField("activationContainer")] + [DataField] public string? ActivationContainer; /// /// How often does sensor update its owners status (in seconds). Limited by the system update rate. /// - [DataField("updateRate")] + [DataField] public TimeSpan UpdateRate = TimeSpan.FromSeconds(2f); /// @@ -56,7 +62,7 @@ public sealed partial class SuitSensorComponent : Component /// /// Next time when sensor updated owners status /// - [DataField("nextUpdate", customTypeSerializer:typeof(TimeOffsetSerializer))] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] [AutoPausedField] public TimeSpan NextUpdate = TimeSpan.Zero; diff --git a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs index dc1bb1124d..2b412654d5 100644 --- a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs +++ b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs @@ -8,10 +8,13 @@ using Content.Server.GameTicking; using Content.Server.Medical.CrewMonitoring; using Content.Server.Popups; using Content.Server.Station.Systems; +using Content.Shared.ActionBlocker; using Content.Shared.Clothing; using Content.Shared.Damage; using Content.Shared.DeviceNetwork; +using Content.Shared.DoAfter; using Content.Shared.Examine; +using Content.Shared.Interaction; using Content.Shared.Medical.SuitSensor; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; @@ -35,6 +38,9 @@ public sealed class SuitSensorSystem : EntitySystem [Dependency] private readonly StationSystem _stationSystem = default!; [Dependency] private readonly SingletonDeviceNetServerSystem _singletonServerSystem = default!; [Dependency] private readonly MobThresholdSystem _mobThresholdSystem = default!; + [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!; public override void Initialize() { @@ -49,6 +55,7 @@ public sealed class SuitSensorSystem : EntitySystem SubscribeLocalEvent(OnRemove); SubscribeLocalEvent(OnEmpPulse); SubscribeLocalEvent(OnEmpFinished); + SubscribeLocalEvent(OnSuitSensorDoAfter); } public override void Update(float frameTime) @@ -205,7 +212,14 @@ public sealed class SuitSensorSystem : EntitySystem return; // standard interaction checks - if (!args.CanAccess || !args.CanInteract || args.Hands == null) + if (!args.CanInteract || args.Hands == null) + return; + + if (!_interactionSystem.InRangeUnobstructed(args.User, args.Target)) + return; + + // check if target is incapacitated (cuffed, dead, etc) + if (component.User != null && args.User != component.User && _actionBlocker.CanInteract(component.User.Value, null)) return; args.Verbs.UnionWith(new[] @@ -239,7 +253,7 @@ public sealed class SuitSensorSystem : EntitySystem args.Disabled = true; component.PreviousMode = component.Mode; - SetSensor(uid, SuitSensorMode.SensorOff, null, component); + SetSensor((uid, component), SuitSensorMode.SensorOff, null); component.PreviousControlsLocked = component.ControlsLocked; component.ControlsLocked = true; @@ -247,7 +261,7 @@ public sealed class SuitSensorSystem : EntitySystem private void OnEmpFinished(EntityUid uid, SuitSensorComponent component, ref EmpDisabledRemoved args) { - SetSensor(uid, component.PreviousMode, null, component); + SetSensor((uid, component), component.PreviousMode, null); component.ControlsLocked = component.PreviousControlsLocked; } @@ -259,7 +273,7 @@ public sealed class SuitSensorSystem : EntitySystem Disabled = component.Mode == mode, Priority = -(int) mode, // sort them in descending order Category = VerbCategory.SetSensor, - Act = () => SetSensor(uid, mode, userUid, component) + Act = () => TrySetSensor((uid, component), mode, userUid) }; } @@ -287,18 +301,46 @@ public sealed class SuitSensorSystem : EntitySystem return Loc.GetString(name); } - public void SetSensor(EntityUid uid, SuitSensorMode mode, EntityUid? userUid = null, - SuitSensorComponent? component = null) + public void TrySetSensor(Entity sensors, SuitSensorMode mode, EntityUid userUid) { - if (!Resolve(uid, ref component)) + var comp = sensors.Comp; + + if (!Resolve(sensors, ref comp)) return; - component.Mode = mode; + if (comp.User == null || userUid == comp.User) + SetSensor(sensors, mode, userUid); + else + { + var doAfterEvent = new SuitSensorChangeDoAfterEvent(mode); + var doAfterArgs = new DoAfterArgs(EntityManager, userUid, comp.SensorsTime, doAfterEvent, sensors) + { + BreakOnMove = true, + BreakOnDamage = true + }; + + _doAfterSystem.TryStartDoAfter(doAfterArgs); + } + } + + private void OnSuitSensorDoAfter(Entity sensors, ref SuitSensorChangeDoAfterEvent args) + { + if (args.Handled || args.Cancelled) + return; + + SetSensor(sensors, args.Mode, args.User); + } + + public void SetSensor(Entity sensors, SuitSensorMode mode, EntityUid? userUid = null) + { + var comp = sensors.Comp; + + comp.Mode = mode; if (userUid != null) { var msg = Loc.GetString("suit-sensor-mode-state", ("mode", GetModeName(mode))); - _popupSystem.PopupEntity(msg, uid, userUid.Value); + _popupSystem.PopupEntity(msg, sensors, userUid.Value); } } diff --git a/Content.Shared/Medical/SuitSensor/SharedSuitSensor.cs b/Content.Shared/Medical/SuitSensor/SharedSuitSensor.cs index 27539dd22b..f48e31756d 100644 --- a/Content.Shared/Medical/SuitSensor/SharedSuitSensor.cs +++ b/Content.Shared/Medical/SuitSensor/SharedSuitSensor.cs @@ -1,3 +1,4 @@ +using Content.Shared.DoAfter; using Robust.Shared.Map; using Robust.Shared.Serialization; @@ -67,3 +68,16 @@ public static class SuitSensorConstants ///Used by the CrewMonitoringServerSystem to send the status of all connected suit sensors to each crew monitor public const string NET_STATUS_COLLECTION = "suit-status-collection"; } + +[Serializable, NetSerializable] +public sealed partial class SuitSensorChangeDoAfterEvent : DoAfterEvent +{ + public SuitSensorMode Mode { get; private set; } = SuitSensorMode.SensorOff; + + public SuitSensorChangeDoAfterEvent(SuitSensorMode mode) + { + Mode = mode; + } + + public override DoAfterEvent Clone() => this; +}