Cuff enhancements (#3087)

* Cuff enhancements

* Cuffs now have an OnClick for the alert to remove them
* nullables
* Use default interaction range so highlights are accurate
* Cuffing fails more gracely
* Make shared abstract and add component references to client / server
* Don't cache AudioSystem and HandsComponent given cuffs are rarely used

* Fix test

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
This commit is contained in:
metalgearsloth
2021-02-06 03:11:21 +11:00
committed by GitHub
parent 9884b14e8d
commit 7ed07c0cac
7 changed files with 121 additions and 74 deletions

View File

@@ -1,4 +1,5 @@
using Content.Shared.GameObjects.Components.ActionBlocking; #nullable enable
using Content.Shared.GameObjects.Components.ActionBlocking;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
@@ -6,9 +7,10 @@ using Robust.Shared.GameObjects;
namespace Content.Client.GameObjects.Components.ActionBlocking namespace Content.Client.GameObjects.Components.ActionBlocking
{ {
[RegisterComponent] [RegisterComponent]
[ComponentReference(typeof(SharedHandcuffComponent))]
public class HandcuffComponent : SharedHandcuffComponent public class HandcuffComponent : SharedHandcuffComponent
{ {
public override void HandleComponentState(ComponentState curState, ComponentState nextState) public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
{ {
if (curState is not HandcuffedComponentState state) if (curState is not HandcuffedComponentState state)
{ {

View File

@@ -18,7 +18,7 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking
[TestFixture] [TestFixture]
[TestOf(typeof(CuffableComponent))] [TestOf(typeof(CuffableComponent))]
[TestOf(typeof(HandcuffComponent))] [TestOf(typeof(HandcuffComponent))]
public class CuffUnitTest : ContentIntegrationTest public class HandCuffTest : ContentIntegrationTest
{ {
private const string PROTOTYPES = @" private const string PROTOTYPES = @"
- type: entity - type: entity
@@ -77,7 +77,7 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking
Assert.True(secondCuffs.TryGetComponent(out secondHandcuff!), $"Second handcuffs has no {nameof(HandcuffComponent)}"); Assert.True(secondCuffs.TryGetComponent(out secondHandcuff!), $"Second handcuffs has no {nameof(HandcuffComponent)}");
// Test to ensure cuffed players register the handcuffs // Test to ensure cuffed players register the handcuffs
cuffed.AddNewCuffs(cuffs); cuffed.TryAddNewCuffs(human, cuffs);
Assert.True(cuffed.CuffedHandCount > 0, "Handcuffing a player did not result in their hands being cuffed"); Assert.True(cuffed.CuffedHandCount > 0, "Handcuffing a player did not result in their hands being cuffed");
// Test to ensure a player with 4 hands will still only have 2 hands cuffed // Test to ensure a player with 4 hands will still only have 2 hands cuffed
@@ -86,7 +86,7 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking
Assert.True(cuffed.CuffedHandCount == 2 && hands.Hands.Count() == 4, "Player doesn't have correct amount of hands cuffed"); Assert.True(cuffed.CuffedHandCount == 2 && hands.Hands.Count() == 4, "Player doesn't have correct amount of hands cuffed");
// Test to give a player with 4 hands 2 sets of cuffs // Test to give a player with 4 hands 2 sets of cuffs
cuffed.AddNewCuffs(secondCuffs); cuffed.TryAddNewCuffs(human, secondCuffs);
Assert.True(cuffed.CuffedHandCount == 4, "Player doesn't have correct amount of hands cuffed"); Assert.True(cuffed.CuffedHandCount == 4, "Player doesn't have correct amount of hands cuffed");
}); });

View File

@@ -0,0 +1,25 @@
#nullable enable
using Content.Server.GameObjects.Components.ActionBlocking;
using Content.Shared.Alert;
using JetBrains.Annotations;
using Robust.Shared.Serialization;
namespace Content.Server.Alert.Click
{
/// <summary>
/// Try to remove handcuffs from yourself
/// </summary>
[UsedImplicitly]
public class RemoveCuffs : IAlertClick
{
public void ExposeData(ObjectSerializer serializer) {}
public void AlertClicked(ClickAlertEventArgs args)
{
if (args.Player.TryGetComponent(out CuffableComponent? cuffableComponent))
{
cuffableComponent.TryUncuff(args.Player);
}
}
}
}

View File

@@ -1,15 +1,13 @@
using System; #nullable enable
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Content.Server.GameObjects.Components.GUI; using Content.Server.GameObjects.Components.GUI;
using Content.Server.GameObjects.Components.Items.Storage;
using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Mobs;
using Content.Server.GameObjects.EntitySystems.DoAfter; using Content.Server.GameObjects.EntitySystems.DoAfter;
using Content.Server.Interfaces.GameObjects.Components.Items; using Content.Server.Interfaces.GameObjects.Components.Items;
using Content.Shared.Alert; using Content.Shared.Alert;
using Content.Shared.GameObjects.Components.ActionBlocking; using Content.Shared.GameObjects.Components.ActionBlocking;
using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.GameObjects.EntitySystems.ActionBlocker; using Content.Shared.GameObjects.EntitySystems.ActionBlocker;
using Content.Shared.GameObjects.Verbs; using Content.Shared.GameObjects.Verbs;
using Content.Shared.Interfaces; using Content.Shared.Interfaces;
@@ -46,24 +44,20 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
[ViewVariables(VVAccess.ReadOnly)] [ViewVariables(VVAccess.ReadOnly)]
private Container _container = default!; private Container _container = default!;
private float _interactRange; // TODO: Make a component message
private IHandsComponent _hands; public event Action? OnCuffedStateChanged;
public event Action OnCuffedStateChanged; private bool _uncuffing;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_container = ContainerManagerComponent.Ensure<Container>(Name, Owner); _container = ContainerManagerComponent.Ensure<Container>(Name, Owner);
_interactRange = SharedInteractionSystem.InteractionRange / 2;
Owner.EntityManager.EventBus.SubscribeEvent<HandCountChangedEvent>(EventSource.Local, this, HandleHandCountChange); Owner.EntityManager.EventBus.SubscribeEvent<HandCountChangedEvent>(EventSource.Local, this, HandleHandCountChange);
if (!Owner.TryGetComponent(out _hands)) Owner.EnsureComponentWarn<HandsComponent>();
{
Logger.Warning("Player does not have an IHandsComponent!");
}
} }
public override ComponentState GetComponentState() public override ComponentState GetComponentState()
@@ -99,27 +93,35 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
/// Add a set of cuffs to an existing CuffedComponent. /// Add a set of cuffs to an existing CuffedComponent.
/// </summary> /// </summary>
/// <param name="prototype"></param> /// <param name="prototype"></param>
public void AddNewCuffs(IEntity handcuff) public bool TryAddNewCuffs(IEntity user, IEntity handcuff)
{ {
if (!handcuff.HasComponent<HandcuffComponent>()) if (!handcuff.HasComponent<HandcuffComponent>())
{ {
Logger.Warning($"Handcuffs being applied to player are missing a {nameof(HandcuffComponent)}!"); Logger.Warning($"Handcuffs being applied to player are missing a {nameof(HandcuffComponent)}!");
return; return false;
} }
if (!handcuff.InRangeUnobstructed(Owner, _interactRange)) if (!handcuff.InRangeUnobstructed(Owner))
{ {
Logger.Warning("Handcuffs being applied to player are obstructed or too far away! This should not happen!"); Logger.Warning("Handcuffs being applied to player are obstructed or too far away! This should not happen!");
return; return true;
}
// Success!
if (user.TryGetComponent(out HandsComponent? handsComponent) && handsComponent.IsHolding(handcuff))
{
// Good lord handscomponent is scuffed, I hope some smug person will fix it someday
handsComponent.Drop(handcuff);
} }
_container.Insert(handcuff); _container.Insert(handcuff);
CanStillInteract = _hands.Hands.Count() > CuffedHandCount; CanStillInteract = Owner.TryGetComponent(out HandsComponent? ownerHands) && ownerHands.Hands.Count() > CuffedHandCount;
OnCuffedStateChanged?.Invoke(); OnCuffedStateChanged?.Invoke();
UpdateAlert(); UpdateAlert();
UpdateHeldItems(); UpdateHeldItems();
Dirty(); Dirty();
return true;
} }
/// <summary> /// <summary>
@@ -128,7 +130,7 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
private void UpdateHandCount() private void UpdateHandCount()
{ {
var dirty = false; var dirty = false;
var handCount = _hands.Hands.Count(); var handCount = Owner.TryGetComponent(out HandsComponent? handsComponent) ? handsComponent.Hands.Count() : 0;
while (CuffedHandCount > handCount && CuffedHandCount > 0) while (CuffedHandCount > handCount && CuffedHandCount > 0)
{ {
@@ -142,7 +144,7 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
if (dirty) if (dirty)
{ {
CanStillInteract = handCount > CuffedHandCount; CanStillInteract = handCount > CuffedHandCount;
OnCuffedStateChanged.Invoke(); OnCuffedStateChanged?.Invoke();
Dirty(); Dirty();
} }
} }
@@ -160,17 +162,19 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
/// </summary> /// </summary>
public void UpdateHeldItems() public void UpdateHeldItems()
{ {
var itemCount = _hands.GetAllHeldItems().Count(); if (!Owner.TryGetComponent(out HandsComponent? handsComponent)) return;
var freeHandCount = _hands.Hands.Count() - CuffedHandCount;
var itemCount = handsComponent.GetAllHeldItems().Count();
var freeHandCount = handsComponent.Hands.Count() - CuffedHandCount;
if (freeHandCount < itemCount) if (freeHandCount < itemCount)
{ {
foreach (var item in _hands.GetAllHeldItems()) foreach (var item in handsComponent.GetAllHeldItems())
{ {
if (freeHandCount < itemCount) if (freeHandCount < itemCount)
{ {
freeHandCount++; freeHandCount++;
_hands.Drop(item.Owner, false); handsComponent.Drop(item.Owner, false);
} }
else else
{ {
@@ -185,7 +189,7 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
/// </summary> /// </summary>
private void UpdateAlert() private void UpdateAlert()
{ {
if (Owner.TryGetComponent(out ServerAlertsComponent status)) if (Owner.TryGetComponent(out ServerAlertsComponent? status))
{ {
if (CanStillInteract) if (CanStillInteract)
{ {
@@ -204,8 +208,10 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
/// </summary> /// </summary>
/// <param name="user">The cuffed entity</param> /// <param name="user">The cuffed entity</param>
/// <param name="cuffsToRemove">Optional param for the handcuff entity to remove from the cuffed entity. If null, uses the most recently added handcuff entity.</param> /// <param name="cuffsToRemove">Optional param for the handcuff entity to remove from the cuffed entity. If null, uses the most recently added handcuff entity.</param>
public async void TryUncuff(IEntity user, IEntity cuffsToRemove = null) public async void TryUncuff(IEntity user, IEntity? cuffsToRemove = null)
{ {
if (_uncuffing) return;
var isOwner = user == Owner; var isOwner = user == Owner;
if (cuffsToRemove == null) if (cuffsToRemove == null)
@@ -232,13 +238,13 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
return; return;
} }
if (!isOwner && !user.InRangeUnobstructed(Owner, _interactRange)) if (!isOwner && !user.InRangeUnobstructed(Owner))
{ {
user.PopupMessage(Loc.GetString("You are too far away to remove the cuffs.")); user.PopupMessage(Loc.GetString("You are too far away to remove the cuffs."));
return; return;
} }
if (!cuffsToRemove.InRangeUnobstructed(Owner, _interactRange)) if (!cuffsToRemove.InRangeUnobstructed(Owner))
{ {
Logger.Warning("Handcuffs being removed from player are obstructed or too far away! This should not happen!"); Logger.Warning("Handcuffs being removed from player are obstructed or too far away! This should not happen!");
return; return;
@@ -247,7 +253,17 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
user.PopupMessage(Loc.GetString("You start removing the cuffs.")); user.PopupMessage(Loc.GetString("You start removing the cuffs."));
var audio = EntitySystem.Get<AudioSystem>(); var audio = EntitySystem.Get<AudioSystem>();
audio.PlayFromEntity(isOwner ? cuff.StartBreakoutSound : cuff.StartUncuffSound, Owner); if (isOwner)
{
if (cuff.StartBreakoutSound != null)
audio.PlayFromEntity(cuff.StartBreakoutSound, Owner);
}
else
{
if (cuff.StartUncuffSound != null)
audio.PlayFromEntity(cuff.StartUncuffSound, Owner);
}
var uncuffTime = isOwner ? cuff.BreakoutTime : cuff.UncuffTime; var uncuffTime = isOwner ? cuff.BreakoutTime : cuff.UncuffTime;
var doAfterEventArgs = new DoAfterEventArgs(user, uncuffTime) var doAfterEventArgs = new DoAfterEventArgs(user, uncuffTime)
@@ -259,11 +275,16 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
}; };
var doAfterSystem = EntitySystem.Get<DoAfterSystem>(); var doAfterSystem = EntitySystem.Get<DoAfterSystem>();
_uncuffing = true;
var result = await doAfterSystem.DoAfter(doAfterEventArgs); var result = await doAfterSystem.DoAfter(doAfterEventArgs);
_uncuffing = false;
if (result != DoAfterStatus.Cancelled) if (result != DoAfterStatus.Cancelled)
{ {
audio.PlayFromEntity(cuff.EndUncuffSound, Owner); if (cuff.EndUncuffSound != null)
audio.PlayFromEntity(cuff.EndUncuffSound, Owner);
_container.ForceRemove(cuffsToRemove); _container.ForceRemove(cuffsToRemove);
cuffsToRemove.Transform.AttachToGridOrMap(); cuffsToRemove.Transform.AttachToGridOrMap();
@@ -276,14 +297,14 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
cuffsToRemove.Name = cuff.BrokenName; cuffsToRemove.Name = cuff.BrokenName;
cuffsToRemove.Description = cuff.BrokenDesc; cuffsToRemove.Description = cuff.BrokenDesc;
if (cuffsToRemove.TryGetComponent<SpriteComponent>(out var sprite)) if (cuffsToRemove.TryGetComponent<SpriteComponent>(out var sprite) && cuff.BrokenState != null)
{ {
sprite.LayerSetState(0, cuff.BrokenState); // TODO: safety check to see if RSI contains the state? sprite.LayerSetState(0, cuff.BrokenState); // TODO: safety check to see if RSI contains the state?
} }
} }
CanStillInteract = _hands.Hands.Count() > CuffedHandCount; CanStillInteract = Owner.TryGetComponent(out HandsComponent? handsComponent) && handsComponent.Hands.Count() > CuffedHandCount;
OnCuffedStateChanged.Invoke(); OnCuffedStateChanged?.Invoke();
UpdateAlert(); UpdateAlert();
Dirty(); Dirty();

View File

@@ -1,10 +1,10 @@
using System; #nullable enable
using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Content.Server.GameObjects.Components.GUI; using Content.Server.GameObjects.Components.GUI;
using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Mobs;
using Content.Server.GameObjects.EntitySystems.DoAfter; using Content.Server.GameObjects.EntitySystems.DoAfter;
using Content.Shared.GameObjects.Components.ActionBlocking; using Content.Shared.GameObjects.Components.ActionBlocking;
using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.GameObjects.EntitySystems.ActionBlocker; using Content.Shared.GameObjects.EntitySystems.ActionBlocker;
using Content.Shared.Interfaces; using Content.Shared.Interfaces;
using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Interfaces.GameObjects.Components;
@@ -14,7 +14,6 @@ using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Systems; using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Log;
using Robust.Shared.Maths; using Robust.Shared.Maths;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
@@ -22,6 +21,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.ActionBlocking namespace Content.Server.GameObjects.Components.ActionBlocking
{ {
[RegisterComponent] [RegisterComponent]
[ComponentReference(typeof(SharedHandcuffComponent))]
public class HandcuffComponent : SharedHandcuffComponent, IAfterInteract public class HandcuffComponent : SharedHandcuffComponent, IAfterInteract
{ {
/// <summary> /// <summary>
@@ -58,31 +58,31 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
/// The path of the RSI file used for the player cuffed overlay. /// The path of the RSI file used for the player cuffed overlay.
/// </summary> /// </summary>
[ViewVariables] [ViewVariables]
public string CuffedRSI { get; set; } public string? CuffedRSI { get; set; }
/// <summary> /// <summary>
/// The iconstate used with the RSI file for the player cuffed overlay. /// The iconstate used with the RSI file for the player cuffed overlay.
/// </summary> /// </summary>
[ViewVariables] [ViewVariables]
public string OverlayIconState { get; set; } public string? OverlayIconState { get; set; }
/// <summary> /// <summary>
/// The iconstate used for broken handcuffs /// The iconstate used for broken handcuffs
/// </summary> /// </summary>
[ViewVariables] [ViewVariables]
public string BrokenState { get; set; } public string? BrokenState { get; set; }
/// <summary> /// <summary>
/// The iconstate used for broken handcuffs /// The iconstate used for broken handcuffs
/// </summary> /// </summary>
[ViewVariables] [ViewVariables]
public string BrokenName { get; set; } public string BrokenName { get; set; } = default!;
/// <summary> /// <summary>
/// The iconstate used for broken handcuffs /// The iconstate used for broken handcuffs
/// </summary> /// </summary>
[ViewVariables] [ViewVariables]
public string BrokenDesc { get; set; } public string BrokenDesc { get; set; } = default!;
[ViewVariables] [ViewVariables]
public bool Broken public bool Broken
@@ -102,25 +102,20 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
} }
} }
public string StartCuffSound { get; set; } public string? StartCuffSound { get; set; }
public string EndCuffSound { get; set; } public string? EndCuffSound { get; set; }
public string StartBreakoutSound { get; set; } public string? StartBreakoutSound { get; set; }
public string StartUncuffSound { get; set; } public string? StartUncuffSound { get; set; }
public string EndUncuffSound { get; set; } public string? EndUncuffSound { get; set; }
public Color Color { get; set; } public Color Color { get; set; }
// Non-exposed data fields // Non-exposed data fields
private bool _isBroken = false; private bool _isBroken = false;
private float _interactRange;
private AudioSystem _audioSystem;
public override void Initialize() /// <summary>
{ /// Used to prevent DoAfter getting spammed.
base.Initialize(); /// </summary>
private bool _cuffing;
_audioSystem = EntitySystem.Get<AudioSystem>();
_interactRange = SharedInteractionSystem.InteractionRange / 2;
}
public override void ExposeData(ObjectSerializer serializer) public override void ExposeData(ObjectSerializer serializer)
{ {
@@ -150,6 +145,8 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
async Task<bool> IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) async Task<bool> IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
{ {
if (_cuffing) return true;
if (eventArgs.Target == null || !ActionBlockerSystem.CanUse(eventArgs.User) || !eventArgs.Target.TryGetComponent<CuffableComponent>(out var cuffed)) if (eventArgs.Target == null || !ActionBlockerSystem.CanUse(eventArgs.User) || !eventArgs.Target.TryGetComponent<CuffableComponent>(out var cuffed))
{ {
return false; return false;
@@ -179,7 +176,7 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
return true; return true;
} }
if (!eventArgs.InRangeUnobstructed(_interactRange, ignoreInsideBlocker: true)) if (!eventArgs.InRangeUnobstructed(ignoreInsideBlocker: true))
{ {
eventArgs.User.PopupMessage(Loc.GetString("You are too far away to use the cuffs!")); eventArgs.User.PopupMessage(Loc.GetString("You are too far away to use the cuffs!"));
return true; return true;
@@ -187,7 +184,9 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
eventArgs.User.PopupMessage(Loc.GetString("You start cuffing {0:theName}.", eventArgs.Target)); eventArgs.User.PopupMessage(Loc.GetString("You start cuffing {0:theName}.", eventArgs.Target));
eventArgs.User.PopupMessage(eventArgs.Target, Loc.GetString("{0:theName} starts cuffing you!", eventArgs.User)); eventArgs.User.PopupMessage(eventArgs.Target, Loc.GetString("{0:theName} starts cuffing you!", eventArgs.User));
_audioSystem.PlayFromEntity(StartCuffSound, Owner);
if (StartCuffSound != null)
EntitySystem.Get<AudioSystem>().PlayFromEntity(StartCuffSound, Owner);
TryUpdateCuff(eventArgs.User, eventArgs.Target, cuffed); TryUpdateCuff(eventArgs.User, eventArgs.Target, cuffed);
return true; return true;
@@ -214,22 +213,21 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
NeedHand = true NeedHand = true
}; };
_cuffing = true;
var result = await EntitySystem.Get<DoAfterSystem>().DoAfter(doAfterEventArgs); var result = await EntitySystem.Get<DoAfterSystem>().DoAfter(doAfterEventArgs);
_cuffing = false;
if (result != DoAfterStatus.Cancelled) if (result != DoAfterStatus.Cancelled)
{ {
_audioSystem.PlayFromEntity(EndCuffSound, Owner); if (cuffs.TryAddNewCuffs(user, Owner))
user.PopupMessage(Loc.GetString("You successfully cuff {0:theName}.", target)); {
target.PopupMessage(Loc.GetString("You have been cuffed by {0:theName}!", user)); if (EndCuffSound != null)
EntitySystem.Get<AudioSystem>().PlayFromEntity(EndCuffSound, Owner);
if (user.TryGetComponent<HandsComponent>(out var hands)) user.PopupMessage(Loc.GetString("You successfully cuff {0:theName}.", target));
{ target.PopupMessage(Loc.GetString("You have been cuffed by {0:theName}!", user));
hands.Drop(Owner);
cuffs.AddNewCuffs(Owner);
}
else
{
Logger.Warning("Unable to remove handcuffs from player's hands! This should not happen!");
} }
} }
else else

View File

@@ -4,7 +4,7 @@ using Robust.Shared.Serialization;
namespace Content.Shared.GameObjects.Components.ActionBlocking namespace Content.Shared.GameObjects.Components.ActionBlocking
{ {
public class SharedHandcuffComponent : Component public abstract class SharedHandcuffComponent : Component
{ {
public override string Name => "Handcuff"; public override string Name => "Handcuff";
public override uint? NetID => ContentNetIDs.HANDCUFFS; public override uint? NetID => ContentNetIDs.HANDCUFFS;

View File

@@ -89,9 +89,10 @@
- type: alert - type: alert
alertType: Handcuffed alertType: Handcuffed
onClick: !type:RemoveCuffs { }
icon: /Textures/Interface/Alerts/Handcuffed/Handcuffed.png icon: /Textures/Interface/Alerts/Handcuffed/Handcuffed.png
name: "[color=yellow]Handcuffed[/color]" name: "[color=yellow]Handcuffed[/color]"
description: "You're [color=yellow]handcuffed[/color] and can't use your hands. If anyone drags you, you won't be able to resist.." description: "You're [color=yellow]handcuffed[/color] and can't use your hands. If anyone drags you, you won't be able to resist."
- type: alert - type: alert
alertType: Buckled alertType: Buckled