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