SSD Players now properly stay asleep when being revived. (#39409)

* Fixes and API changes

* aaaaaaaaaa

* super shitcode

* cleanup

* fix admin logs

---------

Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
This commit is contained in:
Princess Cheeseballs
2026-05-23 01:24:19 -07:00
committed by GitHub
parent 0cdfd7f115
commit c3eba9fa55
6 changed files with 35 additions and 26 deletions
@@ -61,7 +61,7 @@ public sealed partial class StunProviderSystem : SharedStunProviderSystem
_audio.PlayPvs(comp.Sound, target);
_damageable.ChangeDamage(target, comp.StunDamage, origin: uid);
_stun.TryAddParalyzeDuration(target, comp.StunTime);
_stun.TryAddParalyzeDuration(target, comp.StunTime, true);
// short cooldown to prevent instant stunlocking
_useDelay.SetLength((uid, useDelay), comp.Cooldown, id: comp.DelayId);
+12 -6
View File
@@ -73,6 +73,7 @@ public sealed partial class SleepingSystem : EntitySystem
SubscribeLocalEvent<SleepingComponent, StunEndAttemptEvent>(OnStunEndAttempt);
SubscribeLocalEvent<SleepingComponent, StandUpAttemptEvent>(OnStandUpAttempt);
SubscribeLocalEvent<ForcedSleepingStatusEffectComponent, StatusEffectRelayedEvent<MobStateChangedEvent>>(OnStatusMobStateChanged);
SubscribeLocalEvent<ForcedSleepingStatusEffectComponent, StatusEffectAppliedEvent>(OnStatusEffectApplied);
SubscribeLocalEvent<SleepingComponent, UnbuckleAttemptEvent>(OnUnbuckleAttempt);
SubscribeLocalEvent<SleepingComponent, EmoteAttemptEvent>(OnEmoteAttempt);
@@ -269,14 +270,19 @@ public sealed partial class SleepingSystem : EntitySystem
/// </summary>
private void OnMobStateChanged(Entity<SleepingComponent> ent, ref MobStateChangedEvent args)
{
if (args.NewMobState == MobState.Dead)
{
RemComp<SpamEmitSoundComponent>(ent);
RemComp<SleepingComponent>(ent);
return;
}
if (TryComp<SpamEmitSoundComponent>(ent, out var spam))
_emitSound.SetEnabled((ent, spam), args.NewMobState == MobState.Alive);
if (args.NewMobState == MobState.Dead)
RemCompDeferred<SleepingComponent>(ent);
}
private void OnStatusMobStateChanged(Entity<ForcedSleepingStatusEffectComponent> ent, ref StatusEffectRelayedEvent<MobStateChangedEvent> args)
{
if (args.Args.NewMobState == MobState.Dead || HasComp<SleepingComponent>(args.Args.Target))
return;
TrySleeping(args.Args.Target);
}
private void OnStatusEffectApplied(Entity<ForcedSleepingStatusEffectComponent> ent, ref StatusEffectAppliedEvent args)
@@ -397,7 +397,8 @@ public abstract partial class SharedStaminaSystem : EntitySystem
component.Critical = true;
component.StaminaDamage = component.CritThreshold;
StunSystem.TryUpdateParalyzeDuration(uid, component.StunTime);
StunSystem.TryUpdateParalyzeDuration(uid, component.StunTime, true);
// Give them buffer before being able to be re-stunned
component.NextUpdate = Timing.CurTime + component.StunTime + StamCritBufferTime;
@@ -4,6 +4,7 @@ using Content.Shared.Damage.Systems;
using Content.Shared.Eye.Blinding.Systems;
using Content.Shared.Flash;
using Content.Shared.Mobs.Events;
using Content.Shared.Mobs;
using Content.Shared.Movement.Events;
using Content.Shared.Movement.Systems;
using Content.Shared.Rejuvenate;
@@ -25,6 +26,9 @@ public sealed partial class StatusEffectsSystem
SubscribeLocalEvent<StatusEffectContainerComponent, RefreshMovementSpeedModifiersEvent>(RelayStatusEffectEvent);
SubscribeLocalEvent<StatusEffectContainerComponent, UpdateCanMoveEvent>(RelayStatusEffectEvent);
// By Ref Events
SubscribeLocalEvent<StatusEffectContainerComponent, MobStateChangedEvent>(RefRelayStatusEffectEvent);
SubscribeLocalEvent<StatusEffectContainerComponent, RefreshFrictionModifiersEvent>(RefRelayStatusEffectEvent);
SubscribeLocalEvent<StatusEffectContainerComponent, TileFrictionEvent>(RefRelayStatusEffectEvent);
@@ -10,12 +10,6 @@ public abstract partial class SharedStunSystem
{
SubscribeLocalEvent<StunVisualsComponent, MobStateChangedEvent>(OnStunMobStateChanged);
SubscribeLocalEvent<StunVisualsComponent, SleepStateChangedEvent>(OnSleepStateChanged);
SubscribeLocalEvent<StunVisualsComponent, StunnedEvent>(OnStunned);
}
private void OnStunned(Entity<StunVisualsComponent> ent, ref StunnedEvent args)
{
TrySeeingStars(ent.Owner);
}
private bool GetStarsData(Entity<StunVisualsComponent, StunnedComponent?> entity)
@@ -43,7 +37,7 @@ public abstract partial class SharedStunSystem
// Here so server can tell the client to do things
// Don't dirty the component if we don't need to
if (!Appearance.TryGetData<bool>(entity, StunVisuals.SeeingStars, out var stars, entity.Comp) && stars)
if (Appearance.TryGetData<bool>(entity, StunVisuals.SeeingStars, out var stars, entity.Comp) && stars)
return;
if (!Blocker.CanConsciouslyPerformAction(entity))
+15 -11
View File
@@ -1,3 +1,4 @@
using System.Globalization;
using Content.Shared.ActionBlocker;
using Content.Shared.Administration.Logs;
using Content.Shared.Alert;
@@ -127,25 +128,25 @@ public abstract partial class SharedStunSystem : EntitySystem
}
// TODO STUN: Make events for different things. (Getting modifiers, attempt events, informative events...)
public bool TryAddStunDuration(EntityUid uid, TimeSpan duration)
public bool TryAddStunDuration(EntityUid uid, TimeSpan duration, bool visualized = false)
{
if (!_status.TryAddStatusEffectDuration(uid, StunId, duration))
return false;
OnStunnedSuccessfully(uid, duration);
OnStunnedSuccessfully(uid, duration, visualized);
return true;
}
public bool TryUpdateStunDuration(EntityUid uid, TimeSpan? duration)
public bool TryUpdateStunDuration(EntityUid uid, TimeSpan? duration, bool visualized = false)
{
if (!_status.TryUpdateStatusEffectDuration(uid, StunId, duration))
return false;
OnStunnedSuccessfully(uid, duration);
OnStunnedSuccessfully(uid, duration, visualized);
return true;
}
private void OnStunnedSuccessfully(EntityUid uid, TimeSpan? duration)
private void OnStunnedSuccessfully(EntityUid uid, TimeSpan? duration, bool visualized)
{
var ev = new StunnedEvent(); // todo: rename event or change how it is raised - this event is raised each time duration of stun was externally changed
RaiseLocalEvent(uid, ref ev);
@@ -153,8 +154,11 @@ public abstract partial class SharedStunSystem : EntitySystem
var evDropHands = new DropHandItemsEvent();
RaiseLocalEvent(uid, ref evDropHands);
if (visualized)
TrySeeingStars(uid);
var timeForLogs = duration.HasValue
? duration.Value.Seconds.ToString()
? duration.Value.TotalSeconds.ToString(CultureInfo.CurrentCulture)
: "Infinite";
_adminLogger.Add(LogType.Stamina, LogImpact.Medium, $"{ToPrettyString(uid):user} stunned for {timeForLogs} seconds");
}
@@ -282,7 +286,7 @@ public abstract partial class SharedStunSystem : EntitySystem
if (time != null)
{
UpdateKnockdownTime((uid, component), time.Value, refresh);
_adminLogger.Add(LogType.Stamina, LogImpact.Medium, $"{ToPrettyString(uid):user} was knocked down for {time.Value.Seconds} seconds");
_adminLogger.Add(LogType.Stamina, LogImpact.Medium, $"{ToPrettyString(uid):user} was knocked down for {time.Value.TotalSeconds} seconds");
}
else
{
@@ -291,7 +295,7 @@ public abstract partial class SharedStunSystem : EntitySystem
}
}
public bool TryAddParalyzeDuration(EntityUid uid, TimeSpan? duration)
public bool TryAddParalyzeDuration(EntityUid uid, TimeSpan? duration, bool visualized = false)
{
if (duration == null)
return TryUpdateParalyzeDuration(uid, duration);
@@ -301,19 +305,19 @@ public abstract partial class SharedStunSystem : EntitySystem
// We can't exit knockdown when we're stunned, so this prevents knockdown lasting longer than the stun.
Knockdown(uid, null, false, true, true);
OnStunnedSuccessfully(uid, duration);
OnStunnedSuccessfully(uid, duration, visualized);
return true;
}
public bool TryUpdateParalyzeDuration(EntityUid uid, TimeSpan? duration)
public bool TryUpdateParalyzeDuration(EntityUid uid, TimeSpan? duration, bool visualized = false)
{
if (!_status.TryUpdateStatusEffectDuration(uid, StunId, duration))
return false;
// We can't exit knockdown when we're stunned, so this prevents knockdown lasting longer than the stun.
Knockdown(uid, null, false, true, true);
OnStunnedSuccessfully(uid, duration);
OnStunnedSuccessfully(uid, duration, visualized);
return true;
}