Stun and Stamina Visuals (#37196)
* Stun animation * Commit 2 * Almost working commit * Best commit * Minor cleanup and value adjustments * Fix animation data getting wasted and cleaned up some stuff * Don't animate if dead * AppearanceSystem is for chumps * Cleanup * More cleanup * More cleanup * Half working commit * Documentation * Works * ComponentHandleState my beloved * AppearanceComp compatibility * Address review * Borgar * AND NOW THE END IS NEAR * AppearanceSystem compliance (Real) * Don't need to log missing there * I actually hate mob prototypes so much you don't even know --------- Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
a268a4aacc
commit
ac895a0db4
@@ -20,26 +20,27 @@ using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Shared.Damage.Systems;
|
||||
|
||||
public abstract partial class SharedStaminaSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] protected readonly IGameTiming Timing = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly AlertsSystem _alerts = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metadata = default!;
|
||||
[Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
|
||||
[Dependency] private readonly SharedStunSystem _stunSystem = default!;
|
||||
[Dependency] protected readonly SharedStunSystem StunSystem = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly IConfigurationManager _config = default!;
|
||||
|
||||
/// <summary>
|
||||
/// How much of a buffer is there between the stun duration and when stuns can be re-applied.
|
||||
/// </summary>
|
||||
private static readonly TimeSpan StamCritBufferTime = TimeSpan.FromSeconds(3f);
|
||||
protected static readonly TimeSpan StamCritBufferTime = TimeSpan.FromSeconds(3f);
|
||||
|
||||
public float UniversalStaminaDamageModifier { get; private set; } = 1f;
|
||||
|
||||
@@ -66,31 +67,31 @@ public abstract partial class SharedStaminaSystem : EntitySystem
|
||||
Subs.CVar(_config, CCVars.PlaytestStaminaDamageModifier, value => UniversalStaminaDamageModifier = value, true);
|
||||
}
|
||||
|
||||
private void OnStamHandleState(EntityUid uid, StaminaComponent component, ref AfterAutoHandleStateEvent args)
|
||||
protected virtual void OnStamHandleState(Entity<StaminaComponent> entity, ref AfterAutoHandleStateEvent args)
|
||||
{
|
||||
if (component.Critical)
|
||||
EnterStamCrit(uid, component);
|
||||
if (entity.Comp.Critical)
|
||||
EnterStamCrit(entity);
|
||||
else
|
||||
{
|
||||
if (component.StaminaDamage > 0f)
|
||||
EnsureComp<ActiveStaminaComponent>(uid);
|
||||
if (entity.Comp.StaminaDamage > 0f)
|
||||
EnsureComp<ActiveStaminaComponent>(entity);
|
||||
|
||||
ExitStamCrit(uid, component);
|
||||
ExitStamCrit(entity);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnShutdown(EntityUid uid, StaminaComponent component, ComponentShutdown args)
|
||||
protected virtual void OnShutdown(Entity<StaminaComponent> entity, ref ComponentShutdown args)
|
||||
{
|
||||
if (MetaData(uid).EntityLifeStage < EntityLifeStage.Terminating)
|
||||
if (MetaData(entity).EntityLifeStage < EntityLifeStage.Terminating)
|
||||
{
|
||||
RemCompDeferred<ActiveStaminaComponent>(uid);
|
||||
RemCompDeferred<ActiveStaminaComponent>(entity);
|
||||
}
|
||||
_alerts.ClearAlert(uid, component.StaminaAlert);
|
||||
_alerts.ClearAlert(entity, entity.Comp.StaminaAlert);
|
||||
}
|
||||
|
||||
private void OnStartup(EntityUid uid, StaminaComponent component, ComponentStartup args)
|
||||
private void OnStartup(Entity<StaminaComponent> entity, ref ComponentStartup args)
|
||||
{
|
||||
SetStaminaAlert(uid, component);
|
||||
UpdateStaminaVisuals(entity);
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
@@ -99,23 +100,23 @@ public abstract partial class SharedStaminaSystem : EntitySystem
|
||||
if (!Resolve(uid, ref component))
|
||||
return 0f;
|
||||
|
||||
var curTime = _timing.CurTime;
|
||||
var curTime = Timing.CurTime;
|
||||
var pauseTime = _metadata.GetPauseTime(uid);
|
||||
return MathF.Max(0f, component.StaminaDamage - MathF.Max(0f, (float) (curTime - (component.NextUpdate + pauseTime)).TotalSeconds * component.Decay));
|
||||
}
|
||||
|
||||
private void OnRejuvenate(EntityUid uid, StaminaComponent component, RejuvenateEvent args)
|
||||
private void OnRejuvenate(Entity<StaminaComponent> entity, ref RejuvenateEvent args)
|
||||
{
|
||||
if (component.StaminaDamage >= component.CritThreshold)
|
||||
if (entity.Comp.StaminaDamage >= entity.Comp.CritThreshold)
|
||||
{
|
||||
ExitStamCrit(uid, component);
|
||||
ExitStamCrit(entity, entity.Comp);
|
||||
}
|
||||
|
||||
component.StaminaDamage = 0;
|
||||
AdjustSlowdown(uid);
|
||||
RemComp<ActiveStaminaComponent>(uid);
|
||||
SetStaminaAlert(uid, component);
|
||||
Dirty(uid, component);
|
||||
entity.Comp.StaminaDamage = 0;
|
||||
AdjustSlowdown(entity.Owner);
|
||||
RemComp<ActiveStaminaComponent>(entity);
|
||||
UpdateStaminaVisuals(entity);
|
||||
Dirty(entity);
|
||||
}
|
||||
|
||||
private void OnDisarmed(EntityUid uid, StaminaComponent component, ref DisarmedEvent args)
|
||||
@@ -212,6 +213,15 @@ public abstract partial class SharedStaminaSystem : EntitySystem
|
||||
TakeStaminaDamage(target, component.Damage, source: uid, sound: component.Sound);
|
||||
}
|
||||
|
||||
private void UpdateStaminaVisuals(Entity<StaminaComponent> entity)
|
||||
{
|
||||
SetStaminaAlert(entity, entity.Comp);
|
||||
SetStaminaAnimation(entity);
|
||||
}
|
||||
|
||||
// Here so server can properly tell all clients in PVS range to start the animation
|
||||
protected virtual void SetStaminaAnimation(Entity<StaminaComponent> entity){}
|
||||
|
||||
private void SetStaminaAlert(EntityUid uid, StaminaComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component, false) || component.Deleted)
|
||||
@@ -268,7 +278,7 @@ public abstract partial class SharedStaminaSystem : EntitySystem
|
||||
// Reset the decay cooldown upon taking damage.
|
||||
if (oldDamage < component.StaminaDamage)
|
||||
{
|
||||
var nextUpdate = _timing.CurTime + TimeSpan.FromSeconds(component.Cooldown);
|
||||
var nextUpdate = Timing.CurTime + TimeSpan.FromSeconds(component.Cooldown);
|
||||
|
||||
if (component.NextUpdate < nextUpdate)
|
||||
component.NextUpdate = nextUpdate;
|
||||
@@ -276,7 +286,7 @@ public abstract partial class SharedStaminaSystem : EntitySystem
|
||||
|
||||
AdjustSlowdown(uid);
|
||||
|
||||
SetStaminaAlert(uid, component);
|
||||
UpdateStaminaVisuals((uid, component));
|
||||
|
||||
// Checking if the stamina damage has decreased to zero after exiting the stamcrit
|
||||
if (component.AfterCritical && oldDamage > component.StaminaDamage && component.StaminaDamage <= 0f)
|
||||
@@ -330,7 +340,7 @@ public abstract partial class SharedStaminaSystem : EntitySystem
|
||||
|
||||
var stamQuery = GetEntityQuery<StaminaComponent>();
|
||||
var query = EntityQueryEnumerator<ActiveStaminaComponent>();
|
||||
var curTime = _timing.CurTime;
|
||||
var curTime = Timing.CurTime;
|
||||
|
||||
while (query.MoveNext(out var uid, out _))
|
||||
{
|
||||
@@ -371,16 +381,14 @@ public abstract partial class SharedStaminaSystem : EntitySystem
|
||||
return;
|
||||
}
|
||||
|
||||
// To make the difference between a stun and a stamcrit clear
|
||||
// TODO: Mask?
|
||||
|
||||
component.Critical = true;
|
||||
component.StaminaDamage = component.CritThreshold;
|
||||
|
||||
_stunSystem.TryParalyze(uid, component.StunTime, true);
|
||||
if (StunSystem.TryParalyze(uid, component.StunTime, true))
|
||||
StunSystem.TrySeeingStars(uid);
|
||||
|
||||
// Give them buffer before being able to be re-stunned
|
||||
component.NextUpdate = _timing.CurTime + component.StunTime + StamCritBufferTime;
|
||||
component.NextUpdate = Timing.CurTime + component.StunTime + StamCritBufferTime;
|
||||
EnsureComp<ActiveStaminaComponent>(uid);
|
||||
Dirty(uid, component);
|
||||
_adminLogger.Add(LogType.Stamina, LogImpact.Medium, $"{ToPrettyString(uid):user} entered stamina crit");
|
||||
@@ -396,9 +404,9 @@ public abstract partial class SharedStaminaSystem : EntitySystem
|
||||
|
||||
component.Critical = false;
|
||||
component.AfterCritical = true; // Set to true to indicate that stamina will be restored after exiting stamcrit
|
||||
component.NextUpdate = _timing.CurTime;
|
||||
component.NextUpdate = Timing.CurTime;
|
||||
|
||||
SetStaminaAlert(uid, component);
|
||||
UpdateStaminaVisuals((uid, component));
|
||||
Dirty(uid, component);
|
||||
_adminLogger.Add(LogType.Stamina, LogImpact.Low, $"{ToPrettyString(uid):user} recovered from stamina crit");
|
||||
}
|
||||
@@ -427,6 +435,12 @@ public abstract partial class SharedStaminaSystem : EntitySystem
|
||||
closest = thres.Key;
|
||||
}
|
||||
|
||||
_stunSystem.UpdateStunModifiers(ent, ent.Comp.StunModifierThresholds[closest]);
|
||||
StunSystem.UpdateStunModifiers(ent, ent.Comp.StunModifierThresholds[closest]);
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class StaminaAnimationEvent(NetEntity entity) : EntityEventArgs
|
||||
{
|
||||
public NetEntity Entity = entity;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user