Firelock improvements part 1 (#26582)
* Change prying system and pryunpoweredcomp to allow for custom time modifiers This will be useful if I go the route of making firelocks pryable when unpowered instead of just being able to open and close instantly when unpowered. * Make firelocks properly predicted Shared system made. Since atmos checks can only be done on the server we just have it set relevant bools on the component and then dirty it. Ditched atmos checks on trying to open, they now only happen whenever firelocks are updated. * Make firelocks pryable without a crowbar While this usually would only allow you to do this when a door is unpowered, firelocks do not have the airlock component which actually does that check. As such firelocks will always allow you to pry them open/closed by hand. * Clean up System. Change update interval to be based on ticks. Move as much as possible to shared * Make firelocks unable to emergency close for 2 seconds after being pried open * Clean up * More cleanup * Reorganize SharedFirelockSystem methods to match Initialize order --------- Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
using Content.Shared.Doors.Components;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Doors.Components
|
||||
{
|
||||
@@ -7,9 +7,11 @@ namespace Content.Shared.Doors.Components
|
||||
/// auto-closing on depressurization, air/fire alarm interactions, and preventing normal door functions when
|
||||
/// retaining pressure..
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class FirelockComponent : Component
|
||||
{
|
||||
#region Settings
|
||||
|
||||
/// <summary>
|
||||
/// Pry time modifier to be used when the firelock is currently closed due to fire or pressure.
|
||||
/// </summary>
|
||||
@@ -39,5 +41,47 @@ namespace Content.Shared.Doors.Components
|
||||
/// </summary>
|
||||
[DataField("alarmAutoClose"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool AlarmAutoClose = true;
|
||||
|
||||
/// <summary>
|
||||
/// The cooldown duration before a firelock can automatically close due to a hazardous environment after it has
|
||||
/// been pried open. Measured in seconds.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public TimeSpan EmergencyCloseCooldownDuration = TimeSpan.FromSeconds(2);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Set by system
|
||||
|
||||
/// <summary>
|
||||
/// When the firelock will be allowed to automatically close again due to a hazardous environment.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public TimeSpan? EmergencyCloseCooldown;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the firelock can open, or is locked due to its environment.
|
||||
/// </summary>
|
||||
public bool IsLocked => Pressure || Temperature;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the firelock is holding back a hazardous pressure.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool Pressure;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the firelock is holding back extreme temperatures.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool Temperature;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the airlock is powered.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public bool Powered;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ using Content.Shared.Damage;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Doors.Components;
|
||||
using Content.Shared.Emag.Systems;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Physics;
|
||||
using Content.Shared.Popups;
|
||||
@@ -466,7 +465,7 @@ public abstract partial class SharedDoorSystem : EntitySystem
|
||||
|
||||
door.Partial = true;
|
||||
|
||||
// Make sure no entity waled into the airlock when it started closing.
|
||||
// Make sure no entity walked into the airlock when it started closing.
|
||||
if (!CanClose(uid, door))
|
||||
{
|
||||
door.NextStateChange = GameTiming.CurTime + door.OpenTimeTwo;
|
||||
|
||||
125
Content.Shared/Doors/Systems/SharedFirelockSystem.cs
Normal file
125
Content.Shared/Doors/Systems/SharedFirelockSystem.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.Doors.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Prying.Components;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Shared.Doors.Systems;
|
||||
|
||||
public abstract class SharedFirelockSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SharedDoorSystem _doorSystem = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<FirelockComponent, DoorStateChangedEvent>(OnUpdateState);
|
||||
|
||||
// Access/Prying
|
||||
SubscribeLocalEvent<FirelockComponent, BeforeDoorOpenedEvent>(OnBeforeDoorOpened);
|
||||
SubscribeLocalEvent<FirelockComponent, GetPryTimeModifierEvent>(OnDoorGetPryTimeModifier);
|
||||
SubscribeLocalEvent<FirelockComponent, PriedEvent>(OnAfterPried);
|
||||
|
||||
// Visuals
|
||||
SubscribeLocalEvent<FirelockComponent, MapInitEvent>(UpdateVisuals);
|
||||
SubscribeLocalEvent<FirelockComponent, ComponentStartup>(UpdateVisuals);
|
||||
}
|
||||
|
||||
public bool EmergencyPressureStop(EntityUid uid, FirelockComponent? firelock = null, DoorComponent? door = null)
|
||||
{
|
||||
if (!Resolve(uid, ref firelock, ref door))
|
||||
return false;
|
||||
|
||||
if (door.State != DoorState.Open
|
||||
|| firelock.EmergencyCloseCooldown != null
|
||||
&& _gameTiming.CurTime < firelock.EmergencyCloseCooldown)
|
||||
return false;
|
||||
|
||||
if (!_doorSystem.TryClose(uid, door))
|
||||
return false;
|
||||
|
||||
return _doorSystem.OnPartialClose(uid, door);
|
||||
}
|
||||
|
||||
private void OnUpdateState(EntityUid uid, FirelockComponent component, DoorStateChangedEvent args)
|
||||
{
|
||||
var ev = new BeforeDoorAutoCloseEvent();
|
||||
RaiseLocalEvent(uid, ev);
|
||||
UpdateVisuals(uid, component, args);
|
||||
if (ev.Cancelled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_doorSystem.SetNextStateChange(uid, component.AutocloseDelay);
|
||||
}
|
||||
|
||||
#region Access/Prying
|
||||
|
||||
private void OnBeforeDoorOpened(EntityUid uid, FirelockComponent component, BeforeDoorOpenedEvent args)
|
||||
{
|
||||
// Give the Door remote the ability to force a firelock open even if it is holding back dangerous gas
|
||||
var overrideAccess = (args.User != null) && _accessReaderSystem.IsAllowed(args.User.Value, uid);
|
||||
|
||||
if (!component.Powered || (!overrideAccess && component.IsLocked))
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
private void OnDoorGetPryTimeModifier(EntityUid uid, FirelockComponent component, ref GetPryTimeModifierEvent args)
|
||||
{
|
||||
if (component.Temperature)
|
||||
{
|
||||
_popupSystem.PopupClient(Loc.GetString("firelock-component-is-holding-fire-message"),
|
||||
uid, args.User, PopupType.MediumCaution);
|
||||
}
|
||||
else if (component.Pressure)
|
||||
{
|
||||
_popupSystem.PopupClient(Loc.GetString("firelock-component-is-holding-pressure-message"),
|
||||
uid, args.User, PopupType.MediumCaution);
|
||||
}
|
||||
|
||||
if (component.IsLocked)
|
||||
args.PryTimeModifier *= component.LockedPryTimeModifier;
|
||||
}
|
||||
|
||||
private void OnAfterPried(EntityUid uid, FirelockComponent component, ref PriedEvent args)
|
||||
{
|
||||
component.EmergencyCloseCooldown = _gameTiming.CurTime + component.EmergencyCloseCooldownDuration;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Visuals
|
||||
|
||||
private void UpdateVisuals(EntityUid uid, FirelockComponent component, EntityEventArgs args) => UpdateVisuals(uid, component);
|
||||
|
||||
private void UpdateVisuals(EntityUid uid,
|
||||
FirelockComponent? firelock = null,
|
||||
DoorComponent? door = null,
|
||||
AppearanceComponent? appearance = null)
|
||||
{
|
||||
if (!Resolve(uid, ref door, ref appearance, false))
|
||||
return;
|
||||
|
||||
// only bother to check pressure on doors that are some variation of closed.
|
||||
if (door.State != DoorState.Closed
|
||||
&& door.State != DoorState.Welded
|
||||
&& door.State != DoorState.Denying)
|
||||
{
|
||||
_appearance.SetData(uid, DoorVisuals.ClosedLights, false, appearance);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Resolve(uid, ref firelock, ref appearance, false))
|
||||
return;
|
||||
|
||||
_appearance.SetData(uid, DoorVisuals.ClosedLights, firelock.IsLocked, appearance);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -8,4 +8,6 @@ namespace Content.Shared.Prying.Components;
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class PryUnpoweredComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public float PryModifier = 0.1f;
|
||||
}
|
||||
|
||||
@@ -93,17 +93,17 @@ public sealed class PryingSystem : EntitySystem
|
||||
id = null;
|
||||
|
||||
// We don't care about displaying a message if no tool was used.
|
||||
if (!CanPry(target, user, out _))
|
||||
if (!TryComp<PryUnpoweredComponent>(target, out var unpoweredComp) || !CanPry(target, user, out _, unpoweredComp: unpoweredComp))
|
||||
// If we have reached this point we want the event that caused this
|
||||
// to be marked as handled.
|
||||
return true;
|
||||
|
||||
// hand-prying is much slower
|
||||
var modifier = CompOrNull<PryingComponent>(user)?.SpeedModifier ?? 0.1f;
|
||||
var modifier = CompOrNull<PryingComponent>(user)?.SpeedModifier ?? unpoweredComp.PryModifier;
|
||||
return StartPry(target, user, null, modifier, out id);
|
||||
}
|
||||
|
||||
private bool CanPry(EntityUid target, EntityUid user, out string? message, PryingComponent? comp = null)
|
||||
private bool CanPry(EntityUid target, EntityUid user, out string? message, PryingComponent? comp = null, PryUnpoweredComponent? unpoweredComp = null)
|
||||
{
|
||||
BeforePryEvent canev;
|
||||
|
||||
@@ -113,7 +113,7 @@ public sealed class PryingSystem : EntitySystem
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!TryComp<PryUnpoweredComponent>(target, out _))
|
||||
if (!Resolve(target, ref unpoweredComp))
|
||||
{
|
||||
message = null;
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user