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
This commit is contained in:
BombasterDS
2024-08-11 19:04:42 +10:00
committed by GitHub
parent c8f1c22ff2
commit 67253a3fe1
3 changed files with 78 additions and 16 deletions

View File

@@ -14,37 +14,43 @@ public sealed partial class SuitSensorComponent : Component
/// <summary> /// <summary>
/// Choose a random sensor mode when item is spawned. /// Choose a random sensor mode when item is spawned.
/// </summary> /// </summary>
[DataField("randomMode")] [DataField]
public bool RandomMode = true; public bool RandomMode = true;
/// <summary> /// <summary>
/// If true user can't change suit sensor mode /// If true user can't change suit sensor mode
/// </summary> /// </summary>
[DataField("controlsLocked")] [DataField]
public bool ControlsLocked = false; public bool ControlsLocked = false;
/// <summary>
/// How much time it takes to change another player's sensors
/// </summary>
[DataField]
public float SensorsTime = 1.75f;
/// <summary> /// <summary>
/// Current sensor mode. Can be switched by user verbs. /// Current sensor mode. Can be switched by user verbs.
/// </summary> /// </summary>
[DataField("mode")] [DataField]
public SuitSensorMode Mode = SuitSensorMode.SensorOff; public SuitSensorMode Mode = SuitSensorMode.SensorOff;
/// <summary> /// <summary>
/// Activate sensor if user wear it in this slot. /// Activate sensor if user wear it in this slot.
/// </summary> /// </summary>
[DataField("activationSlot")] [DataField]
public string ActivationSlot = "jumpsuit"; public string ActivationSlot = "jumpsuit";
/// <summary> /// <summary>
/// Activate sensor if user has this in a sensor-compatible container. /// Activate sensor if user has this in a sensor-compatible container.
/// </summary> /// </summary>
[DataField("activationContainer")] [DataField]
public string? ActivationContainer; public string? ActivationContainer;
/// <summary> /// <summary>
/// How often does sensor update its owners status (in seconds). Limited by the system update rate. /// How often does sensor update its owners status (in seconds). Limited by the system update rate.
/// </summary> /// </summary>
[DataField("updateRate")] [DataField]
public TimeSpan UpdateRate = TimeSpan.FromSeconds(2f); public TimeSpan UpdateRate = TimeSpan.FromSeconds(2f);
/// <summary> /// <summary>
@@ -56,7 +62,7 @@ public sealed partial class SuitSensorComponent : Component
/// <summary> /// <summary>
/// Next time when sensor updated owners status /// Next time when sensor updated owners status
/// </summary> /// </summary>
[DataField("nextUpdate", customTypeSerializer:typeof(TimeOffsetSerializer))] [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
[AutoPausedField] [AutoPausedField]
public TimeSpan NextUpdate = TimeSpan.Zero; public TimeSpan NextUpdate = TimeSpan.Zero;

View File

@@ -8,10 +8,13 @@ using Content.Server.GameTicking;
using Content.Server.Medical.CrewMonitoring; using Content.Server.Medical.CrewMonitoring;
using Content.Server.Popups; using Content.Server.Popups;
using Content.Server.Station.Systems; using Content.Server.Station.Systems;
using Content.Shared.ActionBlocker;
using Content.Shared.Clothing; using Content.Shared.Clothing;
using Content.Shared.Damage; using Content.Shared.Damage;
using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork;
using Content.Shared.DoAfter;
using Content.Shared.Examine; using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.Medical.SuitSensor; using Content.Shared.Medical.SuitSensor;
using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems; using Content.Shared.Mobs.Systems;
@@ -35,6 +38,9 @@ public sealed class SuitSensorSystem : EntitySystem
[Dependency] private readonly StationSystem _stationSystem = default!; [Dependency] private readonly StationSystem _stationSystem = default!;
[Dependency] private readonly SingletonDeviceNetServerSystem _singletonServerSystem = default!; [Dependency] private readonly SingletonDeviceNetServerSystem _singletonServerSystem = default!;
[Dependency] private readonly MobThresholdSystem _mobThresholdSystem = 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() public override void Initialize()
{ {
@@ -49,6 +55,7 @@ public sealed class SuitSensorSystem : EntitySystem
SubscribeLocalEvent<SuitSensorComponent, EntGotRemovedFromContainerMessage>(OnRemove); SubscribeLocalEvent<SuitSensorComponent, EntGotRemovedFromContainerMessage>(OnRemove);
SubscribeLocalEvent<SuitSensorComponent, EmpPulseEvent>(OnEmpPulse); SubscribeLocalEvent<SuitSensorComponent, EmpPulseEvent>(OnEmpPulse);
SubscribeLocalEvent<SuitSensorComponent, EmpDisabledRemoved>(OnEmpFinished); SubscribeLocalEvent<SuitSensorComponent, EmpDisabledRemoved>(OnEmpFinished);
SubscribeLocalEvent<SuitSensorComponent, SuitSensorChangeDoAfterEvent>(OnSuitSensorDoAfter);
} }
public override void Update(float frameTime) public override void Update(float frameTime)
@@ -205,7 +212,14 @@ public sealed class SuitSensorSystem : EntitySystem
return; return;
// standard interaction checks // 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; return;
args.Verbs.UnionWith(new[] args.Verbs.UnionWith(new[]
@@ -239,7 +253,7 @@ public sealed class SuitSensorSystem : EntitySystem
args.Disabled = true; args.Disabled = true;
component.PreviousMode = component.Mode; component.PreviousMode = component.Mode;
SetSensor(uid, SuitSensorMode.SensorOff, null, component); SetSensor((uid, component), SuitSensorMode.SensorOff, null);
component.PreviousControlsLocked = component.ControlsLocked; component.PreviousControlsLocked = component.ControlsLocked;
component.ControlsLocked = true; component.ControlsLocked = true;
@@ -247,7 +261,7 @@ public sealed class SuitSensorSystem : EntitySystem
private void OnEmpFinished(EntityUid uid, SuitSensorComponent component, ref EmpDisabledRemoved args) 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; component.ControlsLocked = component.PreviousControlsLocked;
} }
@@ -259,7 +273,7 @@ public sealed class SuitSensorSystem : EntitySystem
Disabled = component.Mode == mode, Disabled = component.Mode == mode,
Priority = -(int) mode, // sort them in descending order Priority = -(int) mode, // sort them in descending order
Category = VerbCategory.SetSensor, 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); return Loc.GetString(name);
} }
public void SetSensor(EntityUid uid, SuitSensorMode mode, EntityUid? userUid = null, public void TrySetSensor(Entity<SuitSensorComponent> sensors, SuitSensorMode mode, EntityUid userUid)
SuitSensorComponent? component = null)
{ {
if (!Resolve(uid, ref component)) var comp = sensors.Comp;
if (!Resolve(sensors, ref comp))
return; 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<SuitSensorComponent> sensors, ref SuitSensorChangeDoAfterEvent args)
{
if (args.Handled || args.Cancelled)
return;
SetSensor(sensors, args.Mode, args.User);
}
public void SetSensor(Entity<SuitSensorComponent> sensors, SuitSensorMode mode, EntityUid? userUid = null)
{
var comp = sensors.Comp;
comp.Mode = mode;
if (userUid != null) if (userUid != null)
{ {
var msg = Loc.GetString("suit-sensor-mode-state", ("mode", GetModeName(mode))); var msg = Loc.GetString("suit-sensor-mode-state", ("mode", GetModeName(mode)));
_popupSystem.PopupEntity(msg, uid, userUid.Value); _popupSystem.PopupEntity(msg, sensors, userUid.Value);
} }
} }

View File

@@ -1,3 +1,4 @@
using Content.Shared.DoAfter;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Serialization; 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 ///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"; 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;
}