Makes thieving gloves sneakier (#21398)

* Hidden DoAfters

* Fix formatting warnings

* Hide progress bar and pickup animation

* Copy Hidden field in copy constructor
This commit is contained in:
TemporalOroboros
2023-11-02 19:10:58 -07:00
committed by GitHub
parent 03922175a7
commit 19614453d9
4 changed files with 39 additions and 13 deletions

View File

@@ -4,6 +4,7 @@ using Robust.Client.GameObjects;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Shared.Enums; using Robust.Shared.Enums;
using Robust.Shared.Graphics; using Robust.Shared.Graphics;
using Robust.Client.Player;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Timing; using Robust.Shared.Timing;
using Robust.Shared.Utility; using Robust.Shared.Utility;
@@ -14,6 +15,7 @@ public sealed class DoAfterOverlay : Overlay
{ {
private readonly IEntityManager _entManager; private readonly IEntityManager _entManager;
private readonly IGameTiming _timing; private readonly IGameTiming _timing;
private readonly IPlayerManager _player;
private readonly SharedTransformSystem _transform; private readonly SharedTransformSystem _transform;
private readonly MetaDataSystem _meta; private readonly MetaDataSystem _meta;
@@ -31,13 +33,14 @@ public sealed class DoAfterOverlay : Overlay
public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowFOV; public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowFOV;
public DoAfterOverlay(IEntityManager entManager, IPrototypeManager protoManager, IGameTiming timing) public DoAfterOverlay(IEntityManager entManager, IPrototypeManager protoManager, IGameTiming timing, IPlayerManager player)
{ {
_entManager = entManager; _entManager = entManager;
_timing = timing; _timing = timing;
_player = player;
_transform = _entManager.EntitySysManager.GetEntitySystem<SharedTransformSystem>(); _transform = _entManager.EntitySysManager.GetEntitySystem<SharedTransformSystem>();
_meta = _entManager.EntitySysManager.GetEntitySystem<MetaDataSystem>(); _meta = _entManager.EntitySysManager.GetEntitySystem<MetaDataSystem>();
var sprite = new SpriteSpecifier.Rsi(new ("/Textures/Interface/Misc/progress_bar.rsi"), "icon"); var sprite = new SpriteSpecifier.Rsi(new("/Textures/Interface/Misc/progress_bar.rsi"), "icon");
_barTexture = _entManager.EntitySysManager.GetEntitySystem<SpriteSystem>().Frame0(sprite); _barTexture = _entManager.EntitySysManager.GetEntitySystem<SpriteSystem>().Frame0(sprite);
_shader = protoManager.Index<ShaderPrototype>("unshaded").Instance(); _shader = protoManager.Index<ShaderPrototype>("unshaded").Instance();
@@ -58,6 +61,7 @@ public sealed class DoAfterOverlay : Overlay
var curTime = _timing.CurTime; var curTime = _timing.CurTime;
var bounds = args.WorldAABB.Enlarged(5f); var bounds = args.WorldAABB.Enlarged(5f);
var localEnt = _player.LocalSession?.AttachedEntity;
var metaQuery = _entManager.GetEntityQuery<MetaDataComponent>(); var metaQuery = _entManager.GetEntityQuery<MetaDataComponent>();
var enumerator = _entManager.AllEntityQueryEnumerator<ActiveDoAfterComponent, DoAfterComponent, SpriteComponent, TransformComponent>(); var enumerator = _entManager.AllEntityQueryEnumerator<ActiveDoAfterComponent, DoAfterComponent, SpriteComponent, TransformComponent>();
@@ -88,6 +92,17 @@ public sealed class DoAfterOverlay : Overlay
foreach (var doAfter in comp.DoAfters.Values) foreach (var doAfter in comp.DoAfters.Values)
{ {
// Hide some DoAfters from other players for stealthy actions (ie: thieving gloves)
var alpha = 1f;
if (doAfter.Args.Hidden)
{
if (uid != localEnt)
continue;
// Hints to the local player that this do-after is not visible to other players.
alpha = 0.5f;
}
// Use the sprite itself if we know its bounds. This means short or tall sprites don't get overlapped // Use the sprite itself if we know its bounds. This means short or tall sprites don't get overlapped
// by the bar. // by the bar.
float yOffset = sprite.Bounds.Height / 2f + 0.05f; float yOffset = sprite.Bounds.Height / 2f + 0.05f;
@@ -108,15 +123,15 @@ public sealed class DoAfterOverlay : Overlay
{ {
var elapsed = doAfter.CancelledTime.Value - doAfter.StartTime; var elapsed = doAfter.CancelledTime.Value - doAfter.StartTime;
elapsedRatio = (float) Math.Min(1, elapsed.TotalSeconds / doAfter.Args.Delay.TotalSeconds); elapsedRatio = (float) Math.Min(1, elapsed.TotalSeconds / doAfter.Args.Delay.TotalSeconds);
var cancelElapsed = (time - doAfter.CancelledTime.Value).TotalSeconds; var cancelElapsed = (time - doAfter.CancelledTime.Value).TotalSeconds;
var flash = Math.Floor(cancelElapsed / FlashTime) % 2 == 0; var flash = Math.Floor(cancelElapsed / FlashTime) % 2 == 0;
color = new Color(1f, 0f, 0f, flash ? 1f : 0f); color = new Color(1f, 0f, 0f, flash ? alpha : 0f);
} }
else else
{ {
var elapsed = time - doAfter.StartTime; var elapsed = time - doAfter.StartTime;
elapsedRatio = (float) Math.Min(1, elapsed.TotalSeconds / doAfter.Args.Delay.TotalSeconds); elapsedRatio = (float) Math.Min(1, elapsed.TotalSeconds / doAfter.Args.Delay.TotalSeconds);
color = GetProgressColor(elapsedRatio); color = GetProgressColor(elapsedRatio, alpha);
} }
var xProgress = (EndX - StartX) * elapsedRatio + StartX; var xProgress = (EndX - StartX) * elapsedRatio + StartX;
@@ -131,14 +146,14 @@ public sealed class DoAfterOverlay : Overlay
handle.SetTransform(Matrix3.Identity); handle.SetTransform(Matrix3.Identity);
} }
public static Color GetProgressColor(float progress) public static Color GetProgressColor(float progress, float alpha = 1f)
{ {
if (progress >= 1.0f) if (progress >= 1.0f)
{ {
return new Color(0f, 1f, 0f); return new Color(0f, 1f, 0f, alpha);
} }
// lerp // lerp
var hue = (5f / 18f) * progress; var hue = (5f / 18f) * progress;
return Color.FromHsv((hue, 1f, 0.75f, 1f)); return Color.FromHsv((hue, 1f, 0.75f, alpha));
} }
} }

View File

@@ -21,7 +21,7 @@ public sealed class DoAfterSystem : SharedDoAfterSystem
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_overlay.AddOverlay(new DoAfterOverlay(EntityManager, _prototype, GameTiming)); _overlay.AddOverlay(new DoAfterOverlay(EntityManager, _prototype, GameTiming, _player));
} }
public override void Shutdown() public override void Shutdown()

View File

@@ -221,6 +221,7 @@ namespace Content.Server.Strip
var doAfterArgs = new DoAfterArgs(EntityManager, user, ev.Time, new AwaitedDoAfterEvent(), null, target: target, used: held) var doAfterArgs = new DoAfterArgs(EntityManager, user, ev.Time, new AwaitedDoAfterEvent(), null, target: target, used: held)
{ {
ExtraCheck = Check, ExtraCheck = Check,
Hidden = ev.Stealth,
AttemptFrequency = AttemptFrequency.EveryTick, AttemptFrequency = AttemptFrequency.EveryTick,
BreakOnDamage = true, BreakOnDamage = true,
BreakOnTargetMove = true, BreakOnTargetMove = true,
@@ -294,6 +295,7 @@ namespace Content.Server.Strip
var doAfterArgs = new DoAfterArgs(EntityManager, user, ev.Time, new AwaitedDoAfterEvent(), null, target: target, used: held) var doAfterArgs = new DoAfterArgs(EntityManager, user, ev.Time, new AwaitedDoAfterEvent(), null, target: target, used: held)
{ {
ExtraCheck = Check, ExtraCheck = Check,
Hidden = ev.Stealth,
AttemptFrequency = AttemptFrequency.EveryTick, AttemptFrequency = AttemptFrequency.EveryTick,
BreakOnDamage = true, BreakOnDamage = true,
BreakOnTargetMove = true, BreakOnTargetMove = true,
@@ -308,7 +310,7 @@ namespace Content.Server.Strip
if (result != DoAfterStatus.Finished) return; if (result != DoAfterStatus.Finished) return;
_handsSystem.TryDrop(user, checkActionBlocker: false, handsComp: userHands); _handsSystem.TryDrop(user, checkActionBlocker: false, handsComp: userHands);
_handsSystem.TryPickup(target, held, handName, checkActionBlocker: false, animateUser: true, handsComp: hands); _handsSystem.TryPickup(target, held, handName, checkActionBlocker: false, animateUser: !ev.Stealth, animate: !ev.Stealth, handsComp: hands);
_adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):user} has placed the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s hands"); _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):user} has placed the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s hands");
// hand update will trigger strippable update // hand update will trigger strippable update
} }
@@ -354,6 +356,7 @@ namespace Content.Server.Strip
var doAfterArgs = new DoAfterArgs(EntityManager, user, ev.Time, new AwaitedDoAfterEvent(), null, target: target, used: item) var doAfterArgs = new DoAfterArgs(EntityManager, user, ev.Time, new AwaitedDoAfterEvent(), null, target: target, used: item)
{ {
ExtraCheck = Check, ExtraCheck = Check,
Hidden = ev.Stealth,
AttemptFrequency = AttemptFrequency.EveryTick, AttemptFrequency = AttemptFrequency.EveryTick,
BreakOnDamage = true, BreakOnDamage = true,
BreakOnTargetMove = true, BreakOnTargetMove = true,
@@ -389,7 +392,7 @@ namespace Content.Server.Strip
// Raise a dropped event, so that things like gas tank internals properly deactivate when stripping // Raise a dropped event, so that things like gas tank internals properly deactivate when stripping
RaiseLocalEvent(item, new DroppedEvent(user), true); RaiseLocalEvent(item, new DroppedEvent(user), true);
_handsSystem.PickupOrDrop(user, item); _handsSystem.PickupOrDrop(user, item, animateUser: !ev.Stealth, animate: !ev.Stealth);
_adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):user} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}"); _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):user} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}");
} }
@@ -430,6 +433,7 @@ namespace Content.Server.Strip
var doAfterArgs = new DoAfterArgs(EntityManager, user, ev.Time, new AwaitedDoAfterEvent(), null, target: target, used: item) var doAfterArgs = new DoAfterArgs(EntityManager, user, ev.Time, new AwaitedDoAfterEvent(), null, target: target, used: item)
{ {
ExtraCheck = Check, ExtraCheck = Check,
Hidden = ev.Stealth,
AttemptFrequency = AttemptFrequency.EveryTick, AttemptFrequency = AttemptFrequency.EveryTick,
BreakOnDamage = true, BreakOnDamage = true,
BreakOnTargetMove = true, BreakOnTargetMove = true,
@@ -439,7 +443,7 @@ namespace Content.Server.Strip
DuplicateCondition = DuplicateConditions.SameTool DuplicateCondition = DuplicateConditions.SameTool
}; };
if (Check() && _handsSystem.TryGetHand(target, handName, out var handSlot, hands) && handSlot.HeldEntity != null) if (!ev.Stealth && Check() && _handsSystem.TryGetHand(target, handName, out var handSlot, hands) && handSlot.HeldEntity != null)
{ {
_popup.PopupEntity( _popup.PopupEntity(
Loc.GetString("strippable-component-alert-owner", Loc.GetString("strippable-component-alert-owner",
@@ -456,7 +460,7 @@ namespace Content.Server.Strip
return; return;
_handsSystem.TryDrop(target, item, checkActionBlocker: false, handsComp: hands); _handsSystem.TryDrop(target, item, checkActionBlocker: false, handsComp: hands);
_handsSystem.PickupOrDrop(user, item, handsComp: userHands); _handsSystem.PickupOrDrop(user, item, animateUser: !ev.Stealth, animate: !ev.Stealth, handsComp: userHands);
// hand update will trigger strippable update // hand update will trigger strippable update
_adminLogger.Add(LogType.Stripping, LogImpact.Medium, _adminLogger.Add(LogType.Stripping, LogImpact.Medium,
$"{ToPrettyString(user):user} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}"); $"{ToPrettyString(user):user} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}");

View File

@@ -40,6 +40,12 @@ public sealed partial class DoAfterArgs
public NetEntity? NetUsed; public NetEntity? NetUsed;
/// <summary>
/// Whether the progress bar for this DoAfter should be hidden from other players.
/// </summary>
[DataField]
public bool Hidden;
#region Event options #region Event options
/// <summary> /// <summary>
/// The event that will get raised when the DoAfter has finished. If null, this will simply raise a <see cref="SimpleDoAfterEvent"/> /// The event that will get raised when the DoAfter has finished. If null, this will simply raise a <see cref="SimpleDoAfterEvent"/>
@@ -239,6 +245,7 @@ public sealed partial class DoAfterArgs
Delay = other.Delay; Delay = other.Delay;
Target = other.Target; Target = other.Target;
Used = other.Used; Used = other.Used;
Hidden = other.Hidden;
EventTarget = other.EventTarget; EventTarget = other.EventTarget;
Broadcast = other.Broadcast; Broadcast = other.Broadcast;
NeedHand = other.NeedHand; NeedHand = other.NeedHand;