EasyPry airlocks for arrivals. Now also prying refactor I guess (#19394)
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
using Content.Client.Wires.Visualizers;
|
using Content.Client.Wires.Visualizers;
|
||||||
using Content.Shared.Doors.Components;
|
using Content.Shared.Doors.Components;
|
||||||
using Content.Shared.Doors.Systems;
|
using Content.Shared.Doors.Systems;
|
||||||
|
using Content.Shared.Prying.Components;
|
||||||
using Robust.Client.Animations;
|
using Robust.Client.Animations;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
|
|
||||||
@@ -15,6 +16,13 @@ public sealed class AirlockSystem : SharedAirlockSystem
|
|||||||
base.Initialize();
|
base.Initialize();
|
||||||
SubscribeLocalEvent<AirlockComponent, ComponentStartup>(OnComponentStartup);
|
SubscribeLocalEvent<AirlockComponent, ComponentStartup>(OnComponentStartup);
|
||||||
SubscribeLocalEvent<AirlockComponent, AppearanceChangeEvent>(OnAppearanceChange);
|
SubscribeLocalEvent<AirlockComponent, AppearanceChangeEvent>(OnAppearanceChange);
|
||||||
|
SubscribeLocalEvent<AirlockComponent, BeforePryEvent>(OnAirlockPryAttempt);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAirlockPryAttempt(EntityUid uid, AirlockComponent component, ref BeforePryEvent args)
|
||||||
|
{
|
||||||
|
// TODO: Temporary until airlocks predicted.
|
||||||
|
args.Cancelled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnComponentStartup(EntityUid uid, AirlockComponent comp, ComponentStartup args)
|
private void OnComponentStartup(EntityUid uid, AirlockComponent comp, ComponentStartup args)
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using Content.Server.DeviceLinking.Events;
|
using Content.Server.DeviceLinking.Events;
|
||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
using Content.Server.Power.EntitySystems;
|
using Content.Server.Power.EntitySystems;
|
||||||
using Content.Shared.Tools.Components;
|
|
||||||
using Content.Server.Wires;
|
using Content.Server.Wires;
|
||||||
using Content.Shared.Doors;
|
using Content.Shared.Doors;
|
||||||
using Content.Shared.Doors.Components;
|
using Content.Shared.Doors.Components;
|
||||||
@@ -9,6 +8,7 @@ using Content.Shared.Doors.Systems;
|
|||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Content.Shared.Wires;
|
using Content.Shared.Wires;
|
||||||
|
using Content.Shared.Prying.Components;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Server.Doors.Systems;
|
namespace Content.Server.Doors.Systems;
|
||||||
@@ -31,9 +31,9 @@ public sealed class AirlockSystem : SharedAirlockSystem
|
|||||||
SubscribeLocalEvent<AirlockComponent, DoorStateChangedEvent>(OnStateChanged);
|
SubscribeLocalEvent<AirlockComponent, DoorStateChangedEvent>(OnStateChanged);
|
||||||
SubscribeLocalEvent<AirlockComponent, BeforeDoorOpenedEvent>(OnBeforeDoorOpened);
|
SubscribeLocalEvent<AirlockComponent, BeforeDoorOpenedEvent>(OnBeforeDoorOpened);
|
||||||
SubscribeLocalEvent<AirlockComponent, BeforeDoorDeniedEvent>(OnBeforeDoorDenied);
|
SubscribeLocalEvent<AirlockComponent, BeforeDoorDeniedEvent>(OnBeforeDoorDenied);
|
||||||
SubscribeLocalEvent<AirlockComponent, ActivateInWorldEvent>(OnActivate, before: new [] {typeof(DoorSystem)});
|
SubscribeLocalEvent<AirlockComponent, ActivateInWorldEvent>(OnActivate, before: new[] { typeof(DoorSystem) });
|
||||||
SubscribeLocalEvent<AirlockComponent, DoorGetPryTimeModifierEvent>(OnGetPryMod);
|
SubscribeLocalEvent<AirlockComponent, GetPryTimeModifierEvent>(OnGetPryMod);
|
||||||
SubscribeLocalEvent<AirlockComponent, BeforeDoorPryEvent>(OnDoorPry);
|
SubscribeLocalEvent<AirlockComponent, BeforePryEvent>(OnBeforePry);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,20 +169,18 @@ public sealed class AirlockSystem : SharedAirlockSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnGetPryMod(EntityUid uid, AirlockComponent component, DoorGetPryTimeModifierEvent args)
|
private void OnGetPryMod(EntityUid uid, AirlockComponent component, ref GetPryTimeModifierEvent args)
|
||||||
{
|
{
|
||||||
if (_power.IsPowered(uid))
|
if (_power.IsPowered(uid))
|
||||||
args.PryTimeModifier *= component.PoweredPryModifier;
|
args.PryTimeModifier *= component.PoweredPryModifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDoorPry(EntityUid uid, AirlockComponent component, BeforeDoorPryEvent args)
|
private void OnBeforePry(EntityUid uid, AirlockComponent component, ref BeforePryEvent args)
|
||||||
{
|
{
|
||||||
if (this.IsPowered(uid, EntityManager))
|
if (this.IsPowered(uid, EntityManager) && !args.PryPowered)
|
||||||
{
|
{
|
||||||
if (HasComp<ToolForcePoweredComponent>(args.Tool))
|
Popup.PopupClient(Loc.GetString("airlock-component-cannot-pry-is-powered-message"), uid, args.User);
|
||||||
return;
|
args.Cancelled = true;
|
||||||
Popup.PopupEntity(Loc.GetString("airlock-component-cannot-pry-is-powered-message"), uid, args.User);
|
|
||||||
args.Cancel();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
using Content.Server.Access;
|
using Content.Server.Access;
|
||||||
using Content.Server.Atmos.Components;
|
using Content.Server.Atmos.Components;
|
||||||
using Content.Server.Atmos.EntitySystems;
|
using Content.Server.Atmos.EntitySystems;
|
||||||
using Content.Server.Construction;
|
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Doors;
|
using Content.Shared.Doors;
|
||||||
using Content.Shared.Doors.Components;
|
using Content.Shared.Doors.Components;
|
||||||
using Content.Shared.Doors.Systems;
|
using Content.Shared.Doors.Systems;
|
||||||
using Content.Shared.Emag.Systems;
|
using Content.Shared.Emag.Systems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Tools.Components;
|
|
||||||
using Content.Shared.Verbs;
|
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Power.EntitySystems;
|
using Content.Server.Power.EntitySystems;
|
||||||
@@ -17,6 +14,8 @@ using Content.Shared.Tools;
|
|||||||
using Robust.Shared.Physics.Components;
|
using Robust.Shared.Physics.Components;
|
||||||
using Robust.Shared.Physics.Events;
|
using Robust.Shared.Physics.Events;
|
||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
|
using Content.Shared.Prying.Systems;
|
||||||
|
using Content.Shared.Prying.Components;
|
||||||
using Content.Shared.Tools.Systems;
|
using Content.Shared.Tools.Systems;
|
||||||
|
|
||||||
namespace Content.Server.Doors.Systems;
|
namespace Content.Server.Doors.Systems;
|
||||||
@@ -27,20 +26,19 @@ public sealed class DoorSystem : SharedDoorSystem
|
|||||||
[Dependency] private readonly DoorBoltSystem _bolts = default!;
|
[Dependency] private readonly DoorBoltSystem _bolts = default!;
|
||||||
[Dependency] private readonly AirtightSystem _airtightSystem = default!;
|
[Dependency] private readonly AirtightSystem _airtightSystem = default!;
|
||||||
[Dependency] private readonly SharedToolSystem _toolSystem = default!;
|
[Dependency] private readonly SharedToolSystem _toolSystem = default!;
|
||||||
|
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
||||||
|
[Dependency] private readonly PryingSystem _pryingSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<DoorComponent, InteractUsingEvent>(OnInteractUsing, after: new[] { typeof(ConstructionSystem) });
|
|
||||||
|
|
||||||
// Mob prying doors
|
SubscribeLocalEvent<DoorComponent, BeforePryEvent>(OnBeforeDoorPry);
|
||||||
SubscribeLocalEvent<DoorComponent, GetVerbsEvent<AlternativeVerb>>(OnDoorAltVerb);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<DoorComponent, DoorPryDoAfterEvent>(OnPryFinished);
|
|
||||||
SubscribeLocalEvent<DoorComponent, WeldableAttemptEvent>(OnWeldAttempt);
|
SubscribeLocalEvent<DoorComponent, WeldableAttemptEvent>(OnWeldAttempt);
|
||||||
SubscribeLocalEvent<DoorComponent, WeldableChangedEvent>(OnWeldChanged);
|
SubscribeLocalEvent<DoorComponent, WeldableChangedEvent>(OnWeldChanged);
|
||||||
SubscribeLocalEvent<DoorComponent, GotEmaggedEvent>(OnEmagged);
|
SubscribeLocalEvent<DoorComponent, GotEmaggedEvent>(OnEmagged);
|
||||||
|
SubscribeLocalEvent<DoorComponent, PriedEvent>(OnAfterPry);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnActivate(EntityUid uid, DoorComponent door, ActivateInWorldEvent args)
|
protected override void OnActivate(EntityUid uid, DoorComponent door, ActivateInWorldEvent args)
|
||||||
@@ -49,7 +47,9 @@ public sealed class DoorSystem : SharedDoorSystem
|
|||||||
if (args.Handled || !door.ClickOpen)
|
if (args.Handled || !door.ClickOpen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TryToggleDoor(uid, door, args.User);
|
if (!TryToggleDoor(uid, door, args.User))
|
||||||
|
_pryingSystem.TryPry(uid, args.User, out _);
|
||||||
|
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,24 +108,7 @@ public sealed class DoorSystem : SharedDoorSystem
|
|||||||
Audio.PlayPvs(soundSpecifier, uid, audioParams);
|
Audio.PlayPvs(soundSpecifier, uid, audioParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region DoAfters
|
#region DoAfters
|
||||||
/// <summary>
|
|
||||||
/// Weld or pry open a door.
|
|
||||||
/// </summary>
|
|
||||||
private void OnInteractUsing(EntityUid uid, DoorComponent door, InteractUsingEvent args)
|
|
||||||
{
|
|
||||||
if (args.Handled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!TryComp(args.Used, out ToolComponent? tool))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (tool.Qualities.Contains(door.PryingQuality))
|
|
||||||
{
|
|
||||||
args.Handled = TryPryDoor(uid, args.Used, args.User, door, out _);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnWeldAttempt(EntityUid uid, DoorComponent component, WeldableAttemptEvent args)
|
private void OnWeldAttempt(EntityUid uid, DoorComponent component, WeldableAttemptEvent args)
|
||||||
{
|
{
|
||||||
if (component.CurrentlyCrushing.Count > 0)
|
if (component.CurrentlyCrushing.Count > 0)
|
||||||
@@ -147,69 +130,12 @@ public sealed class DoorSystem : SharedDoorSystem
|
|||||||
SetState(uid, DoorState.Closed, component);
|
SetState(uid, DoorState.Closed, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDoorAltVerb(EntityUid uid, DoorComponent component, GetVerbsEvent<AlternativeVerb> args)
|
private void OnBeforeDoorPry(EntityUid id, DoorComponent door, ref BeforePryEvent args)
|
||||||
{
|
{
|
||||||
if (!args.CanInteract || !args.CanAccess)
|
if (door.State == DoorState.Welded || !door.CanPry)
|
||||||
return;
|
args.Cancelled = true;
|
||||||
|
|
||||||
if (!TryComp<ToolComponent>(args.User, out var tool) || !tool.Qualities.Contains(component.PryingQuality))
|
|
||||||
return;
|
|
||||||
|
|
||||||
args.Verbs.Add(new AlternativeVerb()
|
|
||||||
{
|
|
||||||
Text = Loc.GetString("door-pry"),
|
|
||||||
Impact = LogImpact.Low,
|
|
||||||
Act = () => TryPryDoor(uid, args.User, args.User, component, out _, force: true),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Pry open a door. This does not check if the user is holding the required tool.
|
|
||||||
/// </summary>
|
|
||||||
public bool TryPryDoor(EntityUid target, EntityUid tool, EntityUid user, DoorComponent door, out DoAfterId? id, bool force = false)
|
|
||||||
{
|
|
||||||
id = null;
|
|
||||||
|
|
||||||
if (door.State == DoorState.Welded)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!force)
|
|
||||||
{
|
|
||||||
var canEv = new BeforeDoorPryEvent(user, tool);
|
|
||||||
RaiseLocalEvent(target, canEv, false);
|
|
||||||
|
|
||||||
if (!door.CanPry || canEv.Cancelled)
|
|
||||||
// mark handled, as airlock component will cancel after generating a pop-up & you don't want to pry a tile
|
|
||||||
// under a windoor.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var modEv = new DoorGetPryTimeModifierEvent(user);
|
|
||||||
RaiseLocalEvent(target, modEv, false);
|
|
||||||
|
|
||||||
_adminLog.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(user)} is using {ToPrettyString(tool)} to pry {ToPrettyString(target)} while it is {door.State}"); // TODO move to generic tool use logging in a way that includes door state
|
|
||||||
_toolSystem.UseTool(tool, user, target, TimeSpan.FromSeconds(modEv.PryTimeModifier * door.PryTime), new[] {door.PryingQuality}, new DoorPryDoAfterEvent(), out id);
|
|
||||||
return true; // we might not actually succeeded, but a do-after has started
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPryFinished(EntityUid uid, DoorComponent door, DoAfterEvent args)
|
|
||||||
{
|
|
||||||
if (args.Cancelled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (door.State == DoorState.Closed)
|
|
||||||
{
|
|
||||||
_adminLog.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User)} pried {ToPrettyString(uid)} open"); // TODO move to generic tool use logging in a way that includes door state
|
|
||||||
StartOpening(uid, door);
|
|
||||||
}
|
|
||||||
else if (door.State == DoorState.Open)
|
|
||||||
{
|
|
||||||
_adminLog.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User)} pried {ToPrettyString(uid)} closed"); // TODO move to generic tool use logging in a way that includes door state
|
|
||||||
StartClosing(uid, door);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -233,7 +159,7 @@ public sealed class DoorSystem : SharedDoorSystem
|
|||||||
}
|
}
|
||||||
private void OnEmagged(EntityUid uid, DoorComponent door, ref GotEmaggedEvent args)
|
private void OnEmagged(EntityUid uid, DoorComponent door, ref GotEmaggedEvent args)
|
||||||
{
|
{
|
||||||
if(TryComp<AirlockComponent>(uid, out var airlockComponent))
|
if (TryComp<AirlockComponent>(uid, out var airlockComponent))
|
||||||
{
|
{
|
||||||
if (_bolts.IsBolted(uid) || !this.IsPowered(uid, EntityManager))
|
if (_bolts.IsBolted(uid) || !this.IsPowered(uid, EntityManager))
|
||||||
return;
|
return;
|
||||||
@@ -259,10 +185,27 @@ public sealed class DoorSystem : SharedDoorSystem
|
|||||||
if (door.OpenSound != null)
|
if (door.OpenSound != null)
|
||||||
PlaySound(uid, door.OpenSound, AudioParams.Default.WithVolume(-5), user, predicted);
|
PlaySound(uid, door.OpenSound, AudioParams.Default.WithVolume(-5), user, predicted);
|
||||||
|
|
||||||
if(lastState == DoorState.Emagging && TryComp<DoorBoltComponent>(uid, out var doorBoltComponent))
|
if (lastState == DoorState.Emagging && TryComp<DoorBoltComponent>(uid, out var doorBoltComponent))
|
||||||
_bolts.SetBoltsWithAudio(uid, doorBoltComponent, !doorBoltComponent.BoltsDown);
|
_bolts.SetBoltsWithAudio(uid, doorBoltComponent, !doorBoltComponent.BoltsDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Open or close a door after it has been successfuly pried.
|
||||||
|
/// </summary>
|
||||||
|
private void OnAfterPry(EntityUid uid, DoorComponent door, ref PriedEvent args)
|
||||||
|
{
|
||||||
|
if (door.State == DoorState.Closed)
|
||||||
|
{
|
||||||
|
_adminLog.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User)} pried {ToPrettyString(uid)} open");
|
||||||
|
StartOpening(uid, door, args.User);
|
||||||
|
}
|
||||||
|
else if (door.State == DoorState.Open)
|
||||||
|
{
|
||||||
|
_adminLog.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User)} pried {ToPrettyString(uid)} closed");
|
||||||
|
StartClosing(uid, door, args.User);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void CheckDoorBump(DoorComponent component, PhysicsComponent body)
|
protected override void CheckDoorBump(DoorComponent component, PhysicsComponent body)
|
||||||
{
|
{
|
||||||
var uid = body.Owner;
|
var uid = body.Owner;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ using Microsoft.Extensions.Options;
|
|||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Map.Components;
|
using Robust.Shared.Map.Components;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
|
using Content.Shared.Prying.Components;
|
||||||
|
|
||||||
namespace Content.Server.Doors.Systems
|
namespace Content.Server.Doors.Systems
|
||||||
{
|
{
|
||||||
@@ -38,7 +39,7 @@ namespace Content.Server.Doors.Systems
|
|||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<FirelockComponent, BeforeDoorOpenedEvent>(OnBeforeDoorOpened);
|
SubscribeLocalEvent<FirelockComponent, BeforeDoorOpenedEvent>(OnBeforeDoorOpened);
|
||||||
SubscribeLocalEvent<FirelockComponent, DoorGetPryTimeModifierEvent>(OnDoorGetPryTimeModifier);
|
SubscribeLocalEvent<FirelockComponent, GetPryTimeModifierEvent>(OnDoorGetPryTimeModifier);
|
||||||
SubscribeLocalEvent<FirelockComponent, DoorStateChangedEvent>(OnUpdateState);
|
SubscribeLocalEvent<FirelockComponent, DoorStateChangedEvent>(OnUpdateState);
|
||||||
|
|
||||||
SubscribeLocalEvent<FirelockComponent, BeforeDoorAutoCloseEvent>(OnBeforeDoorAutoclose);
|
SubscribeLocalEvent<FirelockComponent, BeforeDoorAutoCloseEvent>(OnBeforeDoorAutoclose);
|
||||||
@@ -144,7 +145,7 @@ namespace Content.Server.Doors.Systems
|
|||||||
args.Cancel();
|
args.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDoorGetPryTimeModifier(EntityUid uid, FirelockComponent component, DoorGetPryTimeModifierEvent args)
|
private void OnDoorGetPryTimeModifier(EntityUid uid, FirelockComponent component, ref GetPryTimeModifierEvent args)
|
||||||
{
|
{
|
||||||
var state = CheckPressureAndFire(uid, component);
|
var state = CheckPressureAndFire(uid, component);
|
||||||
|
|
||||||
@@ -261,7 +262,7 @@ namespace Content.Server.Doors.Systems
|
|||||||
List<AtmosDirection> directions = new(4);
|
List<AtmosDirection> directions = new(4);
|
||||||
for (var i = 0; i < Atmospherics.Directions; i++)
|
for (var i = 0; i < Atmospherics.Directions; i++)
|
||||||
{
|
{
|
||||||
var dir = (AtmosDirection) (1 << i);
|
var dir = (AtmosDirection)(1 << i);
|
||||||
if (airtight.AirBlockedDirection.HasFlag(dir))
|
if (airtight.AirBlockedDirection.HasFlag(dir))
|
||||||
{
|
{
|
||||||
directions.Add(dir);
|
directions.Add(dir);
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ public sealed partial class NPCSteeringSystem
|
|||||||
// TODO: Use the verb.
|
// TODO: Use the verb.
|
||||||
|
|
||||||
if (door.State != DoorState.Opening)
|
if (door.State != DoorState.Opening)
|
||||||
_doors.TryPryDoor(ent, uid, uid, door, out id, force: true);
|
_pryingSystem.TryPry(ent, uid, out id, uid);
|
||||||
|
|
||||||
component.DoAfterId = id;
|
component.DoAfterId = id;
|
||||||
return SteeringObstacleStatus.Continuing;
|
return SteeringObstacleStatus.Continuing;
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ using Robust.Shared.Random;
|
|||||||
using Robust.Shared.Threading;
|
using Robust.Shared.Threading;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
using Content.Shared.Prying.Systems;
|
||||||
|
|
||||||
namespace Content.Server.NPC.Systems;
|
namespace Content.Server.NPC.Systems;
|
||||||
|
|
||||||
@@ -63,6 +64,7 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
|
|||||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
[Dependency] private readonly SharedCombatModeSystem _combat = default!;
|
[Dependency] private readonly SharedCombatModeSystem _combat = default!;
|
||||||
|
[Dependency] private readonly PryingSystem _pryingSystem = default!;
|
||||||
|
|
||||||
private EntityQuery<FixturesComponent> _fixturesQuery;
|
private EntityQuery<FixturesComponent> _fixturesQuery;
|
||||||
private EntityQuery<MovementSpeedModifierComponent> _modifierQuery;
|
private EntityQuery<MovementSpeedModifierComponent> _modifierQuery;
|
||||||
@@ -148,7 +150,7 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
|
|||||||
|
|
||||||
private void OnDebugRequest(RequestNPCSteeringDebugEvent msg, EntitySessionEventArgs args)
|
private void OnDebugRequest(RequestNPCSteeringDebugEvent msg, EntitySessionEventArgs args)
|
||||||
{
|
{
|
||||||
if (!_admin.IsAdmin((IPlayerSession) args.SenderSession))
|
if (!_admin.IsAdmin((IPlayerSession)args.SenderSession))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (msg.Enabled)
|
if (msg.Enabled)
|
||||||
@@ -440,7 +442,7 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
|
|||||||
if (targetPoly != null &&
|
if (targetPoly != null &&
|
||||||
steering.Coordinates.Position.Equals(Vector2.Zero) &&
|
steering.Coordinates.Position.Equals(Vector2.Zero) &&
|
||||||
TryComp<PhysicsComponent>(uid, out var physics) &&
|
TryComp<PhysicsComponent>(uid, out var physics) &&
|
||||||
_interaction.InRangeUnobstructed(uid, steering.Coordinates.EntityId, range: 30f, (CollisionGroup) physics.CollisionMask))
|
_interaction.InRangeUnobstructed(uid, steering.Coordinates.EntityId, range: 30f, (CollisionGroup)physics.CollisionMask))
|
||||||
{
|
{
|
||||||
steering.CurrentPath.Clear();
|
steering.CurrentPath.Clear();
|
||||||
steering.CurrentPath.Enqueue(targetPoly);
|
steering.CurrentPath.Enqueue(targetPoly);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ using Content.Shared.Tools.Components;
|
|||||||
using Content.Shared.Weapons.Melee;
|
using Content.Shared.Weapons.Melee;
|
||||||
using Content.Shared.Zombies;
|
using Content.Shared.Zombies;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
|
using Content.Shared.Prying.Components;
|
||||||
|
|
||||||
namespace Content.Server.Zombies
|
namespace Content.Server.Zombies
|
||||||
{
|
{
|
||||||
@@ -162,11 +163,12 @@ namespace Content.Server.Zombies
|
|||||||
melee.Damage = dspec;
|
melee.Damage = dspec;
|
||||||
|
|
||||||
// humanoid zombies get to pry open doors and shit
|
// humanoid zombies get to pry open doors and shit
|
||||||
var tool = EnsureComp<ToolComponent>(target);
|
var pryComp = EnsureComp<PryingComponent>(target);
|
||||||
tool.SpeedModifier = 0.75f;
|
pryComp.SpeedModifier = 0.75f;
|
||||||
tool.Qualities = new ("Prying");
|
pryComp.PryPowered = true;
|
||||||
tool.UseSound = new SoundPathSpecifier("/Audio/Items/crowbar.ogg");
|
pryComp.Force = true;
|
||||||
Dirty(tool);
|
|
||||||
|
Dirty(target, pryComp);
|
||||||
}
|
}
|
||||||
|
|
||||||
Dirty(melee);
|
Dirty(melee);
|
||||||
@@ -232,7 +234,7 @@ namespace Content.Server.Zombies
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var htn = EnsureComp<HTNComponent>(target);
|
var htn = EnsureComp<HTNComponent>(target);
|
||||||
htn.RootTask = new HTNCompoundTask() {Task = "SimpleHostileCompound"};
|
htn.RootTask = new HTNCompoundTask() { Task = "SimpleHostileCompound" };
|
||||||
htn.Blackboard.SetValue(NPCBlackboard.Owner, target);
|
htn.Blackboard.SetValue(NPCBlackboard.Owner, target);
|
||||||
_npc.WakeNPC(target, htn);
|
_npc.WakeNPC(target, htn);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ public sealed partial class DoorComponent : Component
|
|||||||
}
|
}
|
||||||
|
|
||||||
var curTime = IoCManager.Resolve<IGameTiming>().CurTime;
|
var curTime = IoCManager.Resolve<IGameTiming>().CurTime;
|
||||||
return (float) (NextStateChange.Value - curTime).TotalSeconds;
|
return (float)(NextStateChange.Value - curTime).TotalSeconds;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
@@ -299,10 +299,10 @@ public sealed partial class DoorComponent : Component
|
|||||||
public bool ClickOpen = true;
|
public bool ClickOpen = true;
|
||||||
|
|
||||||
[DataField("openDrawDepth", customTypeSerializer: typeof(ConstantSerializer<DrawDepthTag>))]
|
[DataField("openDrawDepth", customTypeSerializer: typeof(ConstantSerializer<DrawDepthTag>))]
|
||||||
public int OpenDrawDepth = (int) DrawDepth.DrawDepth.Doors;
|
public int OpenDrawDepth = (int)DrawDepth.DrawDepth.Doors;
|
||||||
|
|
||||||
[DataField("closedDrawDepth", customTypeSerializer: typeof(ConstantSerializer<DrawDepthTag>))]
|
[DataField("closedDrawDepth", customTypeSerializer: typeof(ConstantSerializer<DrawDepthTag>))]
|
||||||
public int ClosedDrawDepth = (int) DrawDepth.DrawDepth.Doors;
|
public int ClosedDrawDepth = (int)DrawDepth.DrawDepth.Doors;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
|
|||||||
@@ -62,35 +62,4 @@ namespace Content.Shared.Doors
|
|||||||
public sealed class BeforeDoorAutoCloseEvent : CancellableEntityEventArgs
|
public sealed class BeforeDoorAutoCloseEvent : CancellableEntityEventArgs
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raised to determine how long the door's pry time should be modified by.
|
|
||||||
/// Multiply PryTimeModifier by the desired amount.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class DoorGetPryTimeModifierEvent : EntityEventArgs
|
|
||||||
{
|
|
||||||
public readonly EntityUid User;
|
|
||||||
public float PryTimeModifier = 1.0f;
|
|
||||||
|
|
||||||
public DoorGetPryTimeModifierEvent(EntityUid user)
|
|
||||||
{
|
|
||||||
User = user;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raised when an attempt to pry open the door is made.
|
|
||||||
/// Cancel to stop the door from being pried open.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class BeforeDoorPryEvent : CancellableEntityEventArgs
|
|
||||||
{
|
|
||||||
public readonly EntityUid User;
|
|
||||||
public readonly EntityUid Tool;
|
|
||||||
|
|
||||||
public BeforeDoorPryEvent(EntityUid user, EntityUid tool)
|
|
||||||
{
|
|
||||||
User = user;
|
|
||||||
Tool = tool;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Content.Shared.Doors.Components;
|
using Content.Shared.Doors.Components;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Prying.Components;
|
||||||
|
|
||||||
namespace Content.Shared.Doors.Systems;
|
namespace Content.Shared.Doors.Systems;
|
||||||
|
|
||||||
@@ -16,16 +17,16 @@ public abstract class SharedDoorBoltSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<DoorBoltComponent, BeforeDoorOpenedEvent>(OnBeforeDoorOpened);
|
SubscribeLocalEvent<DoorBoltComponent, BeforeDoorOpenedEvent>(OnBeforeDoorOpened);
|
||||||
SubscribeLocalEvent<DoorBoltComponent, BeforeDoorClosedEvent>(OnBeforeDoorClosed);
|
SubscribeLocalEvent<DoorBoltComponent, BeforeDoorClosedEvent>(OnBeforeDoorClosed);
|
||||||
SubscribeLocalEvent<DoorBoltComponent, BeforeDoorDeniedEvent>(OnBeforeDoorDenied);
|
SubscribeLocalEvent<DoorBoltComponent, BeforeDoorDeniedEvent>(OnBeforeDoorDenied);
|
||||||
SubscribeLocalEvent<DoorBoltComponent, BeforeDoorPryEvent>(OnDoorPry);
|
SubscribeLocalEvent<DoorBoltComponent, BeforePryEvent>(OnDoorPry);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDoorPry(EntityUid uid, DoorBoltComponent component, BeforeDoorPryEvent args)
|
private void OnDoorPry(EntityUid uid, DoorBoltComponent component, ref BeforePryEvent args)
|
||||||
{
|
{
|
||||||
if (component.BoltsDown)
|
if (component.BoltsDown && !args.Force)
|
||||||
{
|
{
|
||||||
Popup.PopupEntity(Loc.GetString("airlock-component-cannot-pry-is-bolted-message"), uid, args.User);
|
Popup.PopupClient(Loc.GetString("airlock-component-cannot-pry-is-bolted-message"), uid, args.User);
|
||||||
args.Cancel();
|
args.Cancelled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ using Robust.Shared.Physics.Events;
|
|||||||
using Robust.Shared.Physics.Systems;
|
using Robust.Shared.Physics.Systems;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
using Content.Shared.Prying.Components;
|
||||||
|
|
||||||
namespace Content.Shared.Doors.Systems;
|
namespace Content.Shared.Doors.Systems;
|
||||||
|
|
||||||
@@ -61,6 +62,8 @@ public abstract partial class SharedDoorSystem : EntitySystem
|
|||||||
|
|
||||||
SubscribeLocalEvent<DoorComponent, StartCollideEvent>(HandleCollide);
|
SubscribeLocalEvent<DoorComponent, StartCollideEvent>(HandleCollide);
|
||||||
SubscribeLocalEvent<DoorComponent, PreventCollideEvent>(PreventCollision);
|
SubscribeLocalEvent<DoorComponent, PreventCollideEvent>(PreventCollision);
|
||||||
|
SubscribeLocalEvent<DoorComponent, GetPryTimeModifierEvent>(OnPryTimeModifier);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnComponentInit(EntityUid uid, DoorComponent door, ComponentInit args)
|
protected virtual void OnComponentInit(EntityUid uid, DoorComponent door, ComponentInit args)
|
||||||
@@ -182,6 +185,11 @@ public abstract partial class SharedDoorSystem : EntitySystem
|
|||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnPryTimeModifier(EntityUid uid, DoorComponent door, ref GetPryTimeModifierEvent args)
|
||||||
|
{
|
||||||
|
args.BaseTime = door.PryTime;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Update the door state/visuals and play an access denied sound when a user without access interacts with the
|
/// Update the door state/visuals and play an access denied sound when a user without access interacts with the
|
||||||
/// door.
|
/// door.
|
||||||
@@ -206,6 +214,7 @@ public abstract partial class SharedDoorSystem : EntitySystem
|
|||||||
PlaySound(uid, door.DenySound, AudioParams.Default.WithVolume(-3), user, predicted);
|
PlaySound(uid, door.DenySound, AudioParams.Default.WithVolume(-3), user, predicted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public bool TryToggleDoor(EntityUid uid, DoorComponent? door = null, EntityUid? user = null, bool predicted = false)
|
public bool TryToggleDoor(EntityUid uid, DoorComponent? door = null, EntityUid? user = null, bool predicted = false)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref door))
|
if (!Resolve(uid, ref door))
|
||||||
@@ -246,7 +255,7 @@ public abstract partial class SharedDoorSystem : EntitySystem
|
|||||||
if (door.State == DoorState.Welded)
|
if (door.State == DoorState.Welded)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var ev = new BeforeDoorOpenedEvent(){User=user};
|
var ev = new BeforeDoorOpenedEvent() { User = user };
|
||||||
RaiseLocalEvent(uid, ev, false);
|
RaiseLocalEvent(uid, ev, false);
|
||||||
if (ev.Cancelled)
|
if (ev.Cancelled)
|
||||||
return false;
|
return false;
|
||||||
@@ -261,6 +270,14 @@ public abstract partial class SharedDoorSystem : EntitySystem
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Immediately start opening a door
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uid"> The uid of the door</param>
|
||||||
|
/// <param name="door"> The doorcomponent of the door</param>
|
||||||
|
/// <param name="user"> The user (if any) opening the door</param>
|
||||||
|
/// <param name="predicted">Whether the interaction would have been
|
||||||
|
/// predicted. See comments in the PlaySound method on the Server system for details</param>
|
||||||
public virtual void StartOpening(EntityUid uid, DoorComponent? door = null, EntityUid? user = null, bool predicted = false)
|
public virtual void StartOpening(EntityUid uid, DoorComponent? door = null, EntityUid? user = null, bool predicted = false)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref door))
|
if (!Resolve(uid, ref door))
|
||||||
@@ -309,6 +326,14 @@ public abstract partial class SharedDoorSystem : EntitySystem
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Immediately start closing a door
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uid"> The uid of the door</param>
|
||||||
|
/// <param name="door"> The doorcomponent of the door</param>
|
||||||
|
/// <param name="user"> The user (if any) opening the door</param>
|
||||||
|
/// <param name="predicted">Whether the interaction would have been
|
||||||
|
/// predicted. See comments in the PlaySound method on the Server system for details</param>
|
||||||
public bool CanClose(EntityUid uid, DoorComponent? door = null, EntityUid? user = null, bool quiet = true)
|
public bool CanClose(EntityUid uid, DoorComponent? door = null, EntityUid? user = null, bool quiet = true)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref door))
|
if (!Resolve(uid, ref door))
|
||||||
@@ -444,11 +469,11 @@ public abstract partial class SharedDoorSystem : EntitySystem
|
|||||||
|
|
||||||
//TODO: Make only shutters ignore these objects upon colliding instead of all airlocks
|
//TODO: Make only shutters ignore these objects upon colliding instead of all airlocks
|
||||||
// Excludes Glasslayer for windows, GlassAirlockLayer for windoors, TableLayer for tables
|
// Excludes Glasslayer for windows, GlassAirlockLayer for windoors, TableLayer for tables
|
||||||
if (!otherPhysics.CanCollide || otherPhysics.CollisionLayer == (int) CollisionGroup.GlassLayer || otherPhysics.CollisionLayer == (int) CollisionGroup.GlassAirlockLayer || otherPhysics.CollisionLayer == (int) CollisionGroup.TableLayer)
|
if (!otherPhysics.CanCollide || otherPhysics.CollisionLayer == (int)CollisionGroup.GlassLayer || otherPhysics.CollisionLayer == (int)CollisionGroup.GlassAirlockLayer || otherPhysics.CollisionLayer == (int)CollisionGroup.TableLayer)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
//If the colliding entity is a slippable item ignore it by the airlock
|
//If the colliding entity is a slippable item ignore it by the airlock
|
||||||
if (otherPhysics.CollisionLayer == (int) CollisionGroup.SlipLayer && otherPhysics.CollisionMask == (int) CollisionGroup.ItemMask)
|
if (otherPhysics.CollisionLayer == (int)CollisionGroup.SlipLayer && otherPhysics.CollisionMask == (int)CollisionGroup.ItemMask)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ((physics.CollisionMask & otherPhysics.CollisionLayer) == 0 && (otherPhysics.CollisionMask & physics.CollisionLayer) == 0)
|
if ((physics.CollisionMask & otherPhysics.CollisionLayer) == 0 && (otherPhysics.CollisionMask & physics.CollisionLayer) == 0)
|
||||||
@@ -598,7 +623,7 @@ public abstract partial class SharedDoorSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void CheckDoorBump(DoorComponent component, PhysicsComponent body) {}
|
protected virtual void CheckDoorBump(DoorComponent component, PhysicsComponent body) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Makes a door proceed to the next state (if applicable).
|
/// Makes a door proceed to the next state (if applicable).
|
||||||
@@ -659,9 +684,4 @@ public abstract partial class SharedDoorSystem : EntitySystem
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
protected abstract void PlaySound(EntityUid uid, SoundSpecifier soundSpecifier, AudioParams audioParams, EntityUid? predictingPlayer, bool predicted);
|
protected abstract void PlaySound(EntityUid uid, SoundSpecifier soundSpecifier, AudioParams audioParams, EntityUid? predictingPlayer, bool predicted);
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
protected sealed partial class DoorPryDoAfterEvent : SimpleDoAfterEvent
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
11
Content.Shared/Prying/Components/PryUnpoweredComponent.cs
Normal file
11
Content.Shared/Prying/Components/PryUnpoweredComponent.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
|
namespace Content.Shared.Prying.Components;
|
||||||
|
|
||||||
|
///<summary>
|
||||||
|
/// Applied to entities that can be pried open without tools while unpowered
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
public sealed partial class PryUnpoweredComponent : Component
|
||||||
|
{
|
||||||
|
}
|
||||||
82
Content.Shared/Prying/Components/PryingComponent.cs
Normal file
82
Content.Shared/Prying/Components/PryingComponent.cs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
|
namespace Content.Shared.Prying.Components;
|
||||||
|
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
public sealed partial class PryingComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the entity can pry open powered doors
|
||||||
|
/// </summary>
|
||||||
|
[DataField("pryPowered")]
|
||||||
|
public bool PryPowered = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the tool can bypass certain restrictions when prying.
|
||||||
|
/// For example door bolts.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("force")]
|
||||||
|
public bool Force = false;
|
||||||
|
/// <summary>
|
||||||
|
/// Modifier on the prying time.
|
||||||
|
/// Lower values result in more time.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("speedModifier")]
|
||||||
|
public float SpeedModifier = 1.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// What sound to play when prying is finished.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("useSound")]
|
||||||
|
public SoundSpecifier UseSound = new SoundPathSpecifier("/Audio/Items/crowbar.ogg");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the entity can currently pry things.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("enabled")]
|
||||||
|
public bool Enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised directed on an entity before prying it.
|
||||||
|
/// Cancel to stop the entity from being pried open.
|
||||||
|
/// </summary>
|
||||||
|
[ByRefEvent]
|
||||||
|
public record struct BeforePryEvent(EntityUid User, bool PryPowered, bool Force)
|
||||||
|
{
|
||||||
|
public readonly EntityUid User = User;
|
||||||
|
|
||||||
|
public readonly bool PryPowered = PryPowered;
|
||||||
|
|
||||||
|
public readonly bool Force = Force;
|
||||||
|
|
||||||
|
public bool Cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised directed on an entity that has been pried.
|
||||||
|
/// </summary>
|
||||||
|
[ByRefEvent]
|
||||||
|
public readonly record struct PriedEvent(EntityUid User)
|
||||||
|
{
|
||||||
|
public readonly EntityUid User = User;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised to determine how long the door's pry time should be modified by.
|
||||||
|
/// Multiply PryTimeModifier by the desired amount.
|
||||||
|
/// </summary>
|
||||||
|
[ByRefEvent]
|
||||||
|
public record struct GetPryTimeModifierEvent
|
||||||
|
{
|
||||||
|
public readonly EntityUid User;
|
||||||
|
public float PryTimeModifier = 1.0f;
|
||||||
|
public float BaseTime = 5.0f;
|
||||||
|
|
||||||
|
public GetPryTimeModifierEvent(EntityUid user)
|
||||||
|
{
|
||||||
|
User = user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
162
Content.Shared/Prying/Systems/PryingSystem.cs
Normal file
162
Content.Shared/Prying/Systems/PryingSystem.cs
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
using Content.Shared.Prying.Components;
|
||||||
|
using Content.Shared.Verbs;
|
||||||
|
using Content.Shared.DoAfter;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Content.Shared.Administration.Logs;
|
||||||
|
using Content.Shared.Database;
|
||||||
|
using Content.Shared.Doors.Components;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using PryUnpoweredComponent = Content.Shared.Prying.Components.PryUnpoweredComponent;
|
||||||
|
|
||||||
|
namespace Content.Shared.Prying.Systems;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles prying of entities (e.g. doors)
|
||||||
|
/// </summary>
|
||||||
|
public sealed class PryingSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly ISharedAdminLogManager _adminLog = default!;
|
||||||
|
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
||||||
|
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
// Mob prying doors
|
||||||
|
SubscribeLocalEvent<DoorComponent, GetVerbsEvent<AlternativeVerb>>(OnDoorAltVerb);
|
||||||
|
SubscribeLocalEvent<DoorComponent, DoorPryDoAfterEvent>(OnDoAfter);
|
||||||
|
SubscribeLocalEvent<DoorComponent, InteractUsingEvent>(TryPryDoor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TryPryDoor(EntityUid uid, DoorComponent comp, InteractUsingEvent args)
|
||||||
|
{
|
||||||
|
if (args.Handled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.Handled = TryPry(uid, args.User, out _, args.Used);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDoorAltVerb(EntityUid uid, DoorComponent component, GetVerbsEvent<AlternativeVerb> args)
|
||||||
|
{
|
||||||
|
if (!args.CanInteract || !args.CanAccess)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp<PryingComponent>(args.User, out var tool))
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.Verbs.Add(new AlternativeVerb()
|
||||||
|
{
|
||||||
|
Text = Loc.GetString("door-pry"),
|
||||||
|
Impact = LogImpact.Low,
|
||||||
|
Act = () => TryPry(uid, args.User, out _, args.User),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempt to pry an entity.
|
||||||
|
/// </summary>
|
||||||
|
public bool TryPry(EntityUid target, EntityUid user, out DoAfterId? id, EntityUid tool)
|
||||||
|
{
|
||||||
|
id = null;
|
||||||
|
|
||||||
|
PryingComponent? comp = null;
|
||||||
|
if (!Resolve(tool, ref comp, false))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!comp.Enabled)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!CanPry(target, user, comp))
|
||||||
|
{
|
||||||
|
// If we have reached this point we want the event that caused this
|
||||||
|
// to be marked as handled as a popup would be generated on failure.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
StartPry(target, user, tool, comp.SpeedModifier, out id);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Try to pry an entity.
|
||||||
|
/// </summary>
|
||||||
|
public bool TryPry(EntityUid target, EntityUid user, out DoAfterId? id)
|
||||||
|
{
|
||||||
|
id = null;
|
||||||
|
|
||||||
|
if (!CanPry(target, user))
|
||||||
|
// If we have reached this point we want the event that caused this
|
||||||
|
// to be marked as handled as a popup would be generated on failure.
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return StartPry(target, user, null, 1.0f, out id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CanPry(EntityUid target, EntityUid user, PryingComponent? comp = null)
|
||||||
|
{
|
||||||
|
BeforePryEvent canev;
|
||||||
|
|
||||||
|
if (comp != null)
|
||||||
|
{
|
||||||
|
canev = new BeforePryEvent(user, comp.PryPowered, comp.Force);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!TryComp<PryUnpoweredComponent>(target, out _))
|
||||||
|
return false;
|
||||||
|
canev = new BeforePryEvent(user, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
RaiseLocalEvent(target, ref canev);
|
||||||
|
|
||||||
|
if (canev.Cancelled)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool StartPry(EntityUid target, EntityUid user, EntityUid? tool, float toolModifier, [NotNullWhen(true)] out DoAfterId? id)
|
||||||
|
{
|
||||||
|
var modEv = new GetPryTimeModifierEvent(user);
|
||||||
|
|
||||||
|
RaiseLocalEvent(target, ref modEv);
|
||||||
|
var doAfterArgs = new DoAfterArgs(EntityManager, user, TimeSpan.FromSeconds(modEv.BaseTime * modEv.PryTimeModifier / toolModifier), new DoorPryDoAfterEvent(), target, target, tool)
|
||||||
|
{
|
||||||
|
BreakOnDamage = true,
|
||||||
|
BreakOnUserMove = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (tool != null)
|
||||||
|
{
|
||||||
|
_adminLog.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(user)} is using {ToPrettyString(tool.Value)} to pry {ToPrettyString(target)}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_adminLog.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(user)} is prying {ToPrettyString(target)}");
|
||||||
|
}
|
||||||
|
return _doAfterSystem.TryStartDoAfter(doAfterArgs, out id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDoAfter(EntityUid uid, DoorComponent door, DoorPryDoAfterEvent args)
|
||||||
|
{
|
||||||
|
if (args.Cancelled)
|
||||||
|
return;
|
||||||
|
if (args.Target is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PryingComponent? comp = null;
|
||||||
|
|
||||||
|
if (args.Used != null && Resolve(args.Used.Value, ref comp))
|
||||||
|
_audioSystem.PlayPredicted(comp.UseSound, args.Used.Value, args.User);
|
||||||
|
|
||||||
|
var ev = new PriedEvent(args.User);
|
||||||
|
RaiseLocalEvent(uid, ref ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed partial class DoorPryDoAfterEvent : SimpleDoAfterEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ using System.Linq;
|
|||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Tools.Components;
|
using Content.Shared.Tools.Components;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
|
using Content.Shared.Prying.Components;
|
||||||
|
|
||||||
namespace Content.Shared.Tools;
|
namespace Content.Shared.Tools;
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ public abstract partial class SharedToolSystem : EntitySystem
|
|||||||
private void OnMultipleToolStartup(EntityUid uid, MultipleToolComponent multiple, ComponentStartup args)
|
private void OnMultipleToolStartup(EntityUid uid, MultipleToolComponent multiple, ComponentStartup args)
|
||||||
{
|
{
|
||||||
// Only set the multiple tool if we have a tool component.
|
// Only set the multiple tool if we have a tool component.
|
||||||
if(EntityManager.TryGetComponent(uid, out ToolComponent? tool))
|
if (EntityManager.TryGetComponent(uid, out ToolComponent? tool))
|
||||||
SetMultipleTool(uid, multiple, tool);
|
SetMultipleTool(uid, multiple, tool);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +53,7 @@ public abstract partial class SharedToolSystem : EntitySystem
|
|||||||
if (multiple.Entries.Length == 0)
|
if (multiple.Entries.Length == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
multiple.CurrentEntry = (uint) ((multiple.CurrentEntry + 1) % multiple.Entries.Length);
|
multiple.CurrentEntry = (uint)((multiple.CurrentEntry + 1) % multiple.Entries.Length);
|
||||||
SetMultipleTool(uid, multiple, playSound: true, user: user);
|
SetMultipleTool(uid, multiple, playSound: true, user: user);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -79,6 +80,19 @@ public abstract partial class SharedToolSystem : EntitySystem
|
|||||||
tool.UseSound = current.Sound;
|
tool.UseSound = current.Sound;
|
||||||
tool.Qualities = current.Behavior;
|
tool.Qualities = current.Behavior;
|
||||||
|
|
||||||
|
// TODO: Replace this with a better solution later
|
||||||
|
if (TryComp<PryingComponent>(uid, out var pcomp))
|
||||||
|
{
|
||||||
|
if (current.Behavior.Contains("Prying"))
|
||||||
|
{
|
||||||
|
pcomp.Enabled = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pcomp.Enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (playSound && current.ChangeSound != null)
|
if (playSound && current.ChangeSound != null)
|
||||||
_audioSystem.PlayPredicted(current.ChangeSound, uid, user);
|
_audioSystem.PlayPredicted(current.ChangeSound, uid, user);
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
- type: Tool
|
- type: Tool
|
||||||
qualities:
|
qualities:
|
||||||
- Prying
|
- Prying
|
||||||
|
- type: Prying
|
||||||
- type: MultipleTool
|
- type: MultipleTool
|
||||||
statusShowBehavior: true
|
statusShowBehavior: true
|
||||||
entries:
|
entries:
|
||||||
|
|||||||
@@ -25,6 +25,11 @@
|
|||||||
speed: 1.5
|
speed: 1.5
|
||||||
qualities:
|
qualities:
|
||||||
- Prying
|
- Prying
|
||||||
|
- type: Prying
|
||||||
|
pryPowered: !type:Bool
|
||||||
|
true
|
||||||
|
force: !type:Bool
|
||||||
|
true
|
||||||
useSound:
|
useSound:
|
||||||
path: /Audio/Items/crowbar.ogg
|
path: /Audio/Items/crowbar.ogg
|
||||||
- type: Reactive
|
- type: Reactive
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
name: haycutters
|
name: haycutters
|
||||||
parent: BaseItem
|
parent: BaseItem
|
||||||
id: Haycutters
|
id: Haycutters
|
||||||
@@ -98,6 +98,7 @@
|
|||||||
path: /Audio/Items/crowbar.ogg
|
path: /Audio/Items/crowbar.ogg
|
||||||
speed: 0.05
|
speed: 0.05
|
||||||
- type: TilePrying
|
- type: TilePrying
|
||||||
|
- type: Prying
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: mooltitool
|
name: mooltitool
|
||||||
|
|||||||
@@ -24,6 +24,12 @@
|
|||||||
- Prying
|
- Prying
|
||||||
speed: 1.5
|
speed: 1.5
|
||||||
useSound: /Audio/Items/jaws_pry.ogg
|
useSound: /Audio/Items/jaws_pry.ogg
|
||||||
|
- type: Prying
|
||||||
|
pryPowered: !type:Bool
|
||||||
|
true
|
||||||
|
force: !type:Bool
|
||||||
|
true
|
||||||
|
useSound: /Audio/Items/jaws_pry.ogg
|
||||||
- type: ToolForcePowered
|
- type: ToolForcePowered
|
||||||
- type: MultipleTool
|
- type: MultipleTool
|
||||||
statusShowBehavior: true
|
statusShowBehavior: true
|
||||||
|
|||||||
@@ -155,6 +155,7 @@
|
|||||||
Steel: 100
|
Steel: 100
|
||||||
- type: StaticPrice
|
- type: StaticPrice
|
||||||
price: 22
|
price: 22
|
||||||
|
- type: Prying
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: Crowbar
|
parent: Crowbar
|
||||||
|
|||||||
@@ -20,3 +20,4 @@
|
|||||||
- type: Tool
|
- type: Tool
|
||||||
qualities:
|
qualities:
|
||||||
- Prying
|
- Prying
|
||||||
|
- type: Prying
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
- Prying
|
- Prying
|
||||||
- type: TilePrying
|
- type: TilePrying
|
||||||
advanced: true
|
advanced: true
|
||||||
|
- type: Prying
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: FireAxeFlaming
|
id: FireAxeFlaming
|
||||||
|
|||||||
@@ -61,6 +61,7 @@
|
|||||||
- type: Tool
|
- type: Tool
|
||||||
qualities:
|
qualities:
|
||||||
- Prying
|
- Prying
|
||||||
|
- type: Prying
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: crusher dagger
|
name: crusher dagger
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
- type: entity
|
||||||
|
parent: AirlockExternal
|
||||||
|
id: AirlockExternalEasyPry
|
||||||
|
suffix: External, EasyPry
|
||||||
|
description: It opens, it closes, it might crush you, and there might be only space behind it. Has to be manually activated. Has a valve labelled "TURN TO OPEN"
|
||||||
|
components:
|
||||||
|
- type: PryUnpowered
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: AirlockExternalGlass
|
||||||
|
id: AirlockExternalGlassEasyPry
|
||||||
|
suffix: External, Glass, EasyPry
|
||||||
|
description: It opens, it closes, it might crush you, and there might be only space behind it. Has to be manually activated. Has a valve labelled "TURN TO OPEN"
|
||||||
|
components:
|
||||||
|
- type: PryUnpowered
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: AirlockGlassShuttle
|
||||||
|
id: AirlockGlassShuttleEasyPry
|
||||||
|
suffix: EasyPry, Docking
|
||||||
|
description: Necessary for connecting two space craft together. Has a valve labelled "TURN TO OPEN"
|
||||||
|
components:
|
||||||
|
- type: PryUnpowered
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: AirlockShuttle
|
||||||
|
id: AirlockShuttleEasyPry
|
||||||
|
suffix: EasyPry, Docking
|
||||||
|
description: Necessary for connecting two space craft together. Has a valve labelled "TURN TO OPEN"
|
||||||
|
components:
|
||||||
|
- type: PryUnpowered
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: AirlockExternalLocked
|
||||||
|
id: AirlockExternalEasyPryLocked
|
||||||
|
suffix: External, EasyPry, Locked
|
||||||
|
description: It opens, it closes, it might crush you, and there might be only space behind it. Has to be manually activated. Has a valve labelled "TURN TO OPEN"
|
||||||
|
components:
|
||||||
|
- type: PryUnpowered
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: AirlockExternalGlassLocked
|
||||||
|
id: AirlockExternalGlassEasyPryLocked
|
||||||
|
suffix: External, Glass, EasyPry, Locked
|
||||||
|
description: It opens, it closes, it might crush you, and there might be only space behind it. Has to be manually activated. Has a valve labelled "TURN TO OPEN"
|
||||||
|
components:
|
||||||
|
- type: PryUnpowered
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: AirlockExternalGlassShuttleLocked
|
||||||
|
id: AirlockGlassShuttleEasyPryLocked
|
||||||
|
suffix: EasyPry, Docking, Locked
|
||||||
|
description: Necessary for connecting two space craft together. Has a valve labelled "TURN TO OPEN"
|
||||||
|
components:
|
||||||
|
- type: PryUnpowered
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: AirlockExternalShuttleLocked
|
||||||
|
id: AirlockShuttleEasyPryLocked
|
||||||
|
suffix: EasyPry, Docking, Locked
|
||||||
|
description: Necessary for connecting two space craft together. Has a valve labelled "TURN TO OPEN"
|
||||||
|
components:
|
||||||
|
- type: PryUnpowered
|
||||||
Reference in New Issue
Block a user