mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-02-14 23:14:45 +01:00
Pry open critical Borgs (#42319)
* One commit ops * Please the maintainer gods * More requested changes * review * actually this is probably a good idea --------- Co-authored-by: ScarKy0 <scarky0@onet.eu>
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
using Content.Shared.Lock.BypassLock.Systems;
|
||||
using Content.Shared.Tools;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Lock.BypassLock.Components;
|
||||
|
||||
/// <summary>
|
||||
/// This component lets the lock on this entity be pried open when the entity is in critical or dead state.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, Access(typeof(BypassLockSystem))]
|
||||
public sealed partial class BypassLockComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The tool quality needed to bypass the lock.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ProtoId<ToolQualityPrototype> BypassingTool = "Prying";
|
||||
|
||||
/// <summary>
|
||||
/// Amount of time in seconds it takes to bypass
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public TimeSpan BypassDelay = TimeSpan.FromSeconds(5f);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Content.Shared.Lock.BypassLock.Systems;
|
||||
using Content.Shared.Mobs;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Lock.BypassLock.Components;
|
||||
|
||||
/// <summary>
|
||||
/// This component lets the lock on this entity be pried open when the entity is in critical or dead state.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, Access(typeof(BypassLockSystem))]
|
||||
public sealed partial class BypassLockRequiresMobStateComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The mobstate where the lock can be bypassed.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public HashSet<MobState> RequiredMobState = [];
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using Content.Shared.Lock.BypassLock.Components;
|
||||
using Content.Shared.Mobs.Components;
|
||||
|
||||
namespace Content.Shared.Lock.BypassLock.Systems;
|
||||
|
||||
public sealed partial class BypassLockSystem
|
||||
{
|
||||
private void InitializeMobStateLockSystem()
|
||||
{
|
||||
SubscribeLocalEvent<BypassLockRequiresMobStateComponent, ForceOpenLockAttemptEvent>(OnForceOpenLockAttempt);
|
||||
SubscribeLocalEvent<BypassLockRequiresMobStateComponent, CheckBypassLockVerbRequirements>(OnGetVerb);
|
||||
}
|
||||
|
||||
private void OnForceOpenLockAttempt(Entity<BypassLockRequiresMobStateComponent> target, ref ForceOpenLockAttemptEvent args)
|
||||
{
|
||||
if (!TryComp<MobStateComponent>(target, out var mobState))
|
||||
return;
|
||||
|
||||
args.CanForceOpen &= target.Comp.RequiredMobState.Contains(mobState.CurrentState);
|
||||
}
|
||||
|
||||
private void OnGetVerb(Entity<BypassLockRequiresMobStateComponent> target, ref CheckBypassLockVerbRequirements args)
|
||||
{
|
||||
if (!TryComp<MobStateComponent>(target, out var mobState))
|
||||
return;
|
||||
|
||||
// Only show disabled verb on a too healthy target when they have the right tool.
|
||||
if (!target.Comp.RequiredMobState.Contains(mobState.CurrentState) && args.RightTool)
|
||||
{
|
||||
args.Verb.Disabled = true;
|
||||
args.Verb.Message = Loc.GetString("bypass-lock-disabled-healthy");
|
||||
}
|
||||
// Show verb of using the wrong tool when the target is critical.
|
||||
else if (target.Comp.RequiredMobState.Contains(mobState.CurrentState) && !args.RightTool)
|
||||
{
|
||||
args.ShowVerb = true;
|
||||
args.Verb.Disabled = true;
|
||||
args.Verb.Message = Loc.GetString("bypass-lock-disabled-wrong-tool", ("quality", args.ToolQuality.ToString().ToLower()));
|
||||
}
|
||||
}
|
||||
}
|
||||
132
Content.Shared/Lock/BypassLock/Systems/BypassLockSystem.cs
Normal file
132
Content.Shared/Lock/BypassLock/Systems/BypassLockSystem.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Lock.BypassLock.Components;
|
||||
using Content.Shared.Tools;
|
||||
using Content.Shared.Tools.Systems;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Lock.BypassLock.Systems;
|
||||
|
||||
public sealed partial class BypassLockSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly LockSystem _lock = default!;
|
||||
[Dependency] private readonly SharedToolSystem _tool = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<BypassLockComponent, InteractUsingEvent>(OnInteractUsing);
|
||||
SubscribeLocalEvent<LockComponent, ForceOpenLockDoAfterEvent>(OnBypassAccessDoAfterEvent);
|
||||
SubscribeLocalEvent<BypassLockComponent, GetVerbsEvent<InteractionVerb>>(OnGetVerb);
|
||||
|
||||
InitializeMobStateLockSystem();
|
||||
}
|
||||
|
||||
private void OnInteractUsing(Entity<BypassLockComponent> target, ref InteractUsingEvent args)
|
||||
{
|
||||
if (target.Owner == args.User)
|
||||
return;
|
||||
|
||||
if (!_tool.HasQuality(args.Used, target.Comp.BypassingTool)
|
||||
|| !_lock.IsLocked(target.Owner))
|
||||
return;
|
||||
|
||||
var ev = new ForceOpenLockAttemptEvent(args.User);
|
||||
RaiseLocalEvent(target.Owner, ref ev);
|
||||
|
||||
if (!ev.CanForceOpen)
|
||||
return;
|
||||
|
||||
args.Handled = TryStartDoAfter(target, args.User, args.Used);
|
||||
}
|
||||
|
||||
private bool TryStartDoAfter(Entity<BypassLockComponent> target, EntityUid user, EntityUid used)
|
||||
{
|
||||
if (!_tool.UseTool(
|
||||
used,
|
||||
user,
|
||||
target,
|
||||
(float) target.Comp.BypassDelay.TotalSeconds,
|
||||
target.Comp.BypassingTool,
|
||||
new ForceOpenLockDoAfterEvent()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_adminLogger.Add(LogType.Action, LogImpact.Low,
|
||||
$"{ToPrettyString(user):user} is prying {ToPrettyString(target):target}'s lock open at {Transform(target).Coordinates:targetlocation}");
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnBypassAccessDoAfterEvent(Entity<LockComponent> target, ref ForceOpenLockDoAfterEvent args)
|
||||
{
|
||||
if (args.Cancelled)
|
||||
return;
|
||||
|
||||
_lock.Unlock(target, args.User, target.Comp);
|
||||
}
|
||||
|
||||
private void OnGetVerb(Entity<BypassLockComponent> target, ref GetVerbsEvent<InteractionVerb> args)
|
||||
{
|
||||
if (!args.CanInteract || !args.CanAccess || args.Using == null)
|
||||
return;
|
||||
|
||||
var rightTool = _tool.HasQuality(args.Using.Value, target.Comp.BypassingTool);
|
||||
var item = args.Using.Value;
|
||||
var bypassVerb = new InteractionVerb
|
||||
{
|
||||
IconEntity = GetNetEntity(item),
|
||||
};
|
||||
|
||||
bypassVerb.Text = bypassVerb.Message = Loc.GetString("bypass-lock-verb");
|
||||
|
||||
var ev = new CheckBypassLockVerbRequirements(bypassVerb, rightTool, rightTool, target.Comp.BypassingTool);
|
||||
RaiseLocalEvent(target, ref ev);
|
||||
|
||||
if (!ev.ShowVerb)
|
||||
return;
|
||||
|
||||
var user = args.User;
|
||||
|
||||
bypassVerb.Act = () => TryStartDoAfter(target, user, item);
|
||||
|
||||
if (!_lock.IsLocked(target.Owner))
|
||||
{
|
||||
bypassVerb.Disabled = true;
|
||||
bypassVerb.Message = Loc.GetString("bypass-lock-disabled-already-open");
|
||||
}
|
||||
|
||||
args.Verbs.Add(bypassVerb);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This event gets raised on the entity with the <see cref="BypassLockRequiresMobStateComponent"/> after someone finished
|
||||
/// a doafter forcing the lock open.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class ForceOpenLockDoAfterEvent : SimpleDoAfterEvent;
|
||||
|
||||
/// <summary>
|
||||
/// This gets raised on the target whose lock is attempted to be forced open.
|
||||
/// </summary>
|
||||
/// <param name="User">Entity attempting to open this.</param>
|
||||
/// <param name="CanForceOpen">Whether the lock can be forced open.</param>
|
||||
[ByRefEvent]
|
||||
public record struct ForceOpenLockAttemptEvent(EntityUid User, bool CanForceOpen = true);
|
||||
|
||||
/// <summary>
|
||||
/// This gets raised on the target that is being right-clicked to check for verb requirements.
|
||||
/// </summary>
|
||||
/// <param name="Verb">The interaction verb that will be shown.</param>
|
||||
/// <param name="RightTool">Whether the tool has the right properties to force the lock open.</param>
|
||||
/// <param name="ShowVerb">Whether the verb should be shown.</param>
|
||||
/// <param name="ToolQuality">The required tool quality to force the lock open.</param>
|
||||
[ByRefEvent]
|
||||
public record struct CheckBypassLockVerbRequirements(InteractionVerb Verb, bool RightTool, bool ShowVerb, ProtoId<ToolQualityPrototype> ToolQuality);
|
||||
4
Resources/Locale/en-US/lock/bypass-lock-component.ftl
Normal file
4
Resources/Locale/en-US/lock/bypass-lock-component.ftl
Normal file
@@ -0,0 +1,4 @@
|
||||
bypass-lock-verb = Force open the access lock
|
||||
bypass-lock-disabled-healthy = The lock needs to be damaged further before it can be forced open.
|
||||
bypass-lock-disabled-wrong-tool = This lock requires {$quality} to be forced open.
|
||||
bypass-lock-disabled-already-open = The lock is already open.
|
||||
@@ -114,7 +114,6 @@
|
||||
- BorgChassis
|
||||
- RoboticsConsole
|
||||
- type: WiresPanel
|
||||
openingTool: Prying
|
||||
- type: ActivatableUIRequiresPanel
|
||||
- type: NameIdentifier
|
||||
group: Silicon
|
||||
@@ -247,6 +246,11 @@
|
||||
damageProtection:
|
||||
flatReductions:
|
||||
Heat: 10 # capable of touching light bulbs and stoves without feeling pain!
|
||||
- type: BypassLock
|
||||
- type: BypassLockRequiresMobState
|
||||
requiredMobState:
|
||||
- Critical
|
||||
- Dead
|
||||
|
||||
- type: entity
|
||||
abstract: true
|
||||
@@ -365,6 +369,8 @@
|
||||
Unsexed: UnisexSiliconSyndicate
|
||||
- type: PointLight
|
||||
color: "#dd200b"
|
||||
- type: BypassLock
|
||||
bypassDelay: 15 # We don't want people to easily be able to remove syndieborg brains.
|
||||
|
||||
- type: entity
|
||||
id: BaseBorgChassisDerelict
|
||||
@@ -422,6 +428,8 @@
|
||||
Unsexed: UnisexSiliconSyndicate
|
||||
- type: PointLight
|
||||
color: "#dd200b"
|
||||
- type: BypassLock
|
||||
bypassDelay: 15 # We don't want people to easily be able to remove syndieborg brains.
|
||||
|
||||
- type: entity
|
||||
parent: BaseBorgChassisNotIonStormable
|
||||
@@ -539,3 +547,5 @@
|
||||
interactSuccessSound:
|
||||
path: /Audio/Ambience/Objects/periodic_beep.ogg
|
||||
- type: Xenoborg
|
||||
- type: BypassLock
|
||||
bypassDelay: 15 # We don't want people to easily be able to remove xenoborg brains.
|
||||
|
||||
Reference in New Issue
Block a user