Skip to content

Commit

Permalink
EasyPry airlocks for arrivals. Now also prying refactor I guess (spac…
Browse files Browse the repository at this point in the history
…e-wizards#19394)

Co-authored-by: metalgearsloth <[email protected]>
  • Loading branch information
nikthechampiongr and metalgearsloth authored Sep 28, 2023
1 parent cbeba20 commit 5ff7912
Show file tree
Hide file tree
Showing 24 changed files with 463 additions and 170 deletions.
8 changes: 8 additions & 0 deletions Content.Client/Doors/AirlockSystem.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Content.Client.Wires.Visualizers;
using Content.Shared.Doors.Components;
using Content.Shared.Doors.Systems;
using Content.Shared.Prying.Components;
using Robust.Client.Animations;
using Robust.Client.GameObjects;

Expand All @@ -15,6 +16,13 @@ public override void Initialize()
base.Initialize();
SubscribeLocalEvent<AirlockComponent, ComponentStartup>(OnComponentStartup);
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)
Expand Down
20 changes: 9 additions & 11 deletions Content.Server/Doors/Systems/AirlockSystem.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
using Content.Server.DeviceLinking.Events;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Shared.Tools.Components;
using Content.Server.Wires;
using Content.Shared.Doors;
using Content.Shared.Doors.Components;
using Content.Shared.Doors.Systems;
using Content.Shared.Interaction;
using Robust.Server.GameObjects;
using Content.Shared.Wires;
using Content.Shared.Prying.Components;
using Robust.Shared.Prototypes;

namespace Content.Server.Doors.Systems;
Expand All @@ -31,9 +31,9 @@ public override void Initialize()
SubscribeLocalEvent<AirlockComponent, DoorStateChangedEvent>(OnStateChanged);
SubscribeLocalEvent<AirlockComponent, BeforeDoorOpenedEvent>(OnBeforeDoorOpened);
SubscribeLocalEvent<AirlockComponent, BeforeDoorDeniedEvent>(OnBeforeDoorDenied);
SubscribeLocalEvent<AirlockComponent, ActivateInWorldEvent>(OnActivate, before: new [] {typeof(DoorSystem)});
SubscribeLocalEvent<AirlockComponent, DoorGetPryTimeModifierEvent>(OnGetPryMod);
SubscribeLocalEvent<AirlockComponent, BeforeDoorPryEvent>(OnDoorPry);
SubscribeLocalEvent<AirlockComponent, ActivateInWorldEvent>(OnActivate, before: new[] { typeof(DoorSystem) });
SubscribeLocalEvent<AirlockComponent, GetPryTimeModifierEvent>(OnGetPryMod);
SubscribeLocalEvent<AirlockComponent, BeforePryEvent>(OnBeforePry);

}

Expand Down Expand Up @@ -169,20 +169,18 @@ private void OnActivate(EntityUid uid, AirlockComponent component, ActivateInWor
}
}

private void OnGetPryMod(EntityUid uid, AirlockComponent component, DoorGetPryTimeModifierEvent args)
private void OnGetPryMod(EntityUid uid, AirlockComponent component, ref GetPryTimeModifierEvent args)
{
if (_power.IsPowered(uid))
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))
return;
Popup.PopupEntity(Loc.GetString("airlock-component-cannot-pry-is-powered-message"), uid, args.User);
args.Cancel();
Popup.PopupClient(Loc.GetString("airlock-component-cannot-pry-is-powered-message"), uid, args.User);
args.Cancelled = true;
}
}

Expand Down
123 changes: 33 additions & 90 deletions Content.Server/Doors/Systems/DoorSystem.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
using Content.Server.Access;
using Content.Server.Atmos.Components;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Construction;
using Content.Shared.Database;
using Content.Shared.Doors;
using Content.Shared.Doors.Components;
using Content.Shared.Doors.Systems;
using Content.Shared.Emag.Systems;
using Content.Shared.Interaction;
using Content.Shared.Tools.Components;
using Content.Shared.Verbs;
using Robust.Shared.Audio;
using Content.Server.Administration.Logs;
using Content.Server.Power.EntitySystems;
using Content.Shared.Tools;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Events;
using Content.Shared.DoAfter;
using Content.Shared.Prying.Systems;
using Content.Shared.Prying.Components;
using Content.Shared.Tools.Systems;

namespace Content.Server.Doors.Systems;
Expand All @@ -27,20 +26,19 @@ public sealed class DoorSystem : SharedDoorSystem
[Dependency] private readonly DoorBoltSystem _bolts = default!;
[Dependency] private readonly AirtightSystem _airtightSystem = default!;
[Dependency] private readonly SharedToolSystem _toolSystem = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
[Dependency] private readonly PryingSystem _pryingSystem = default!;

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<DoorComponent, InteractUsingEvent>(OnInteractUsing, after: new[] { typeof(ConstructionSystem) });

// Mob prying doors
SubscribeLocalEvent<DoorComponent, GetVerbsEvent<AlternativeVerb>>(OnDoorAltVerb);

SubscribeLocalEvent<DoorComponent, DoorPryDoAfterEvent>(OnPryFinished);
SubscribeLocalEvent<DoorComponent, BeforePryEvent>(OnBeforeDoorPry);
SubscribeLocalEvent<DoorComponent, WeldableAttemptEvent>(OnWeldAttempt);
SubscribeLocalEvent<DoorComponent, WeldableChangedEvent>(OnWeldChanged);
SubscribeLocalEvent<DoorComponent, GotEmaggedEvent>(OnEmagged);
SubscribeLocalEvent<DoorComponent, PriedEvent>(OnAfterPry);
}

protected override void OnActivate(EntityUid uid, DoorComponent door, ActivateInWorldEvent args)
Expand All @@ -49,7 +47,9 @@ protected override void OnActivate(EntityUid uid, DoorComponent door, ActivateIn
if (args.Handled || !door.ClickOpen)
return;

TryToggleDoor(uid, door, args.User);
if (!TryToggleDoor(uid, door, args.User))
_pryingSystem.TryPry(uid, args.User, out _);

args.Handled = true;
}

Expand Down Expand Up @@ -108,24 +108,7 @@ protected override void PlaySound(EntityUid uid, SoundSpecifier soundSpecifier,
Audio.PlayPvs(soundSpecifier, uid, audioParams);
}

#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 _);
}
}

#region DoAfters
private void OnWeldAttempt(EntityUid uid, DoorComponent component, WeldableAttemptEvent args)
{
if (component.CurrentlyCrushing.Count > 0)
Expand All @@ -147,69 +130,12 @@ private void OnWeldChanged(EntityUid uid, DoorComponent component, ref WeldableC
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)
return;

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),
});
if (door.State == DoorState.Welded || !door.CanPry)
args.Cancelled = true;
}


/// <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
#endregion


/// <summary>
Expand All @@ -233,7 +159,7 @@ protected override void HandleCollide(EntityUid uid, DoorComponent door, ref Sta
}
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))
return;
Expand All @@ -259,10 +185,27 @@ public override void StartOpening(EntityUid uid, DoorComponent? door = null, Ent
if (door.OpenSound != null)
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);
}

/// <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)
{
var uid = body.Owner;
Expand Down
7 changes: 4 additions & 3 deletions Content.Server/Doors/Systems/FirelockSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using Robust.Server.GameObjects;
using Robust.Shared.Map.Components;
using Robust.Shared.Player;
using Content.Shared.Prying.Components;

namespace Content.Server.Doors.Systems
{
Expand All @@ -38,7 +39,7 @@ public override void Initialize()
base.Initialize();

SubscribeLocalEvent<FirelockComponent, BeforeDoorOpenedEvent>(OnBeforeDoorOpened);
SubscribeLocalEvent<FirelockComponent, DoorGetPryTimeModifierEvent>(OnDoorGetPryTimeModifier);
SubscribeLocalEvent<FirelockComponent, GetPryTimeModifierEvent>(OnDoorGetPryTimeModifier);
SubscribeLocalEvent<FirelockComponent, DoorStateChangedEvent>(OnUpdateState);

SubscribeLocalEvent<FirelockComponent, BeforeDoorAutoCloseEvent>(OnBeforeDoorAutoclose);
Expand Down Expand Up @@ -144,7 +145,7 @@ private void OnBeforeDoorOpened(EntityUid uid, FirelockComponent component, Befo
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);

Expand Down Expand Up @@ -261,7 +262,7 @@ public bool IsHoldingPressureOrFire(EntityUid uid, FirelockComponent firelock)
List<AtmosDirection> directions = new(4);
for (var i = 0; i < Atmospherics.Directions; i++)
{
var dir = (AtmosDirection) (1 << i);
var dir = (AtmosDirection)(1 << i);
if (airtight.AirBlockedDirection.HasFlag(dir))
{
directions.Add(dir);
Expand Down
2 changes: 1 addition & 1 deletion Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ private SteeringObstacleStatus TryHandleFlags(EntityUid uid, NPCSteeringComponen
// TODO: Use the verb.

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;
return SteeringObstacleStatus.Continuing;
Expand Down
6 changes: 4 additions & 2 deletions Content.Server/NPC/Systems/NPCSteeringSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
using Robust.Shared.Threading;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
using Content.Shared.Prying.Systems;

namespace Content.Server.NPC.Systems;

Expand Down Expand Up @@ -63,6 +64,7 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedCombatModeSystem _combat = default!;
[Dependency] private readonly PryingSystem _pryingSystem = default!;

private EntityQuery<FixturesComponent> _fixturesQuery;
private EntityQuery<MovementSpeedModifierComponent> _modifierQuery;
Expand Down Expand Up @@ -148,7 +150,7 @@ public override void Shutdown()

private void OnDebugRequest(RequestNPCSteeringDebugEvent msg, EntitySessionEventArgs args)
{
if (!_admin.IsAdmin((IPlayerSession) args.SenderSession))
if (!_admin.IsAdmin((IPlayerSession)args.SenderSession))
return;

if (msg.Enabled)
Expand Down Expand Up @@ -440,7 +442,7 @@ private async void RequestPath(EntityUid uid, NPCSteeringComponent steering, Tra
if (targetPoly != null &&
steering.Coordinates.Position.Equals(Vector2.Zero) &&
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.Enqueue(targetPoly);
Expand Down
14 changes: 8 additions & 6 deletions Content.Server/Zombies/ZombieSystem.Transform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
using Content.Shared.Weapons.Melee;
using Content.Shared.Zombies;
using Robust.Shared.Audio;
using Content.Shared.Prying.Components;

namespace Content.Server.Zombies
{
Expand Down Expand Up @@ -162,11 +163,12 @@ public void ZombifyEntity(EntityUid target, MobStateComponent? mobState = null)
melee.Damage = dspec;

// humanoid zombies get to pry open doors and shit
var tool = EnsureComp<ToolComponent>(target);
tool.SpeedModifier = 0.75f;
tool.Qualities = new ("Prying");
tool.UseSound = new SoundPathSpecifier("/Audio/Items/crowbar.ogg");
Dirty(tool);
var pryComp = EnsureComp<PryingComponent>(target);
pryComp.SpeedModifier = 0.75f;
pryComp.PryPowered = true;
pryComp.Force = true;

Dirty(target, pryComp);
}

Dirty(melee);
Expand Down Expand Up @@ -232,7 +234,7 @@ public void ZombifyEntity(EntityUid target, MobStateComponent? mobState = null)
else
{
var htn = EnsureComp<HTNComponent>(target);
htn.RootTask = new HTNCompoundTask() {Task = "SimpleHostileCompound"};
htn.RootTask = new HTNCompoundTask() { Task = "SimpleHostileCompound" };
htn.Blackboard.SetValue(NPCBlackboard.Owner, target);
_npc.WakeNPC(target, htn);
}
Expand Down
Loading

0 comments on commit 5ff7912

Please sign in to comment.