New status effect system (#37238)
* spectra * documentation * added into liquid anomaly * Update TemporaryStealthComponent.cs * Update TemporaryStealthComponent.cs * integrated * new system * mark old status effect system as obsolete * ForcedSleeping new status effect * work with reagents * networking??? * Revert "integrated" This reverts commit bca02b82bae18ae131af593d7eb86e6de2745157. * Revert "Update TemporaryStealthComponent.cs" This reverts commit 4a5be8c4b704a0d1ff9544b2e245d8b2701ec580. * Revert "Update TemporaryStealthComponent.cs" This reverts commit a4875bcb41347638854bd723d96a51c3e6d38034. * Revert "added into liquid anomaly" This reverts commit df5086b14bb35f1467158a36807c0f2163a16d99. * Revert "documentation" This reverts commit 3629b9466758cbdfa4dd5e67ece122fa2f181138. * Revert "spectra" This reverts commit 2d03d88c16d16ad6831c19a7921b84600daeb284. * drowsiness status effect remove * reagents work * polish, remove test changes * first Fildrance review part * Update misc.yml * more fildrance review * final part * fix trailing spaces * sleeping status effect * drowsiness status effect * Create ModifyStatusEffect.cs * some tweak * Yay!!! Manual networking * minor nitpick * oopsie * refactor: xml-docs, notnullwhen attributes, whitespaces * fildrance and emo review * refactor: simplify check in SharedStatusEffectsSystem by using pattern matching, TryEffectsWithComp now returns set of Entity<T, StatusEffectComponent> --------- Co-authored-by: pa.pecherskij <pa.pecherskij@interfax.ru>
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
using Content.Shared.Bed.Sleep;
|
||||
using Content.Shared.Drowsiness;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Content.Shared.StatusEffectNew;
|
||||
using Content.Shared.StatusEffectNew.Components;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Enums;
|
||||
@@ -15,11 +17,14 @@ public sealed class DrowsinessOverlay : Overlay
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
private readonly SharedStatusEffectsSystem _statusEffects = default!;
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
public override bool RequestScreenTexture => true;
|
||||
private readonly ShaderInstance _drowsinessShader;
|
||||
|
||||
private EntityQuery<StatusEffectComponent> _statusQuery;
|
||||
|
||||
public float CurrentPower = 0.0f;
|
||||
|
||||
private const float PowerDivisor = 250.0f;
|
||||
@@ -29,6 +34,9 @@ public sealed class DrowsinessOverlay : Overlay
|
||||
public DrowsinessOverlay()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
_statusEffects = _sysMan.GetEntitySystem<SharedStatusEffectsSystem>();
|
||||
|
||||
_statusQuery = _entityManager.GetEntityQuery<StatusEffectComponent>();
|
||||
_drowsinessShader = _prototypeManager.Index<ShaderPrototype>("Drowsiness").InstanceUnique();
|
||||
}
|
||||
|
||||
@@ -39,16 +47,21 @@ public sealed class DrowsinessOverlay : Overlay
|
||||
if (playerEntity == null)
|
||||
return;
|
||||
|
||||
if (!_entityManager.HasComponent<DrowsinessComponent>(playerEntity)
|
||||
|| !_entityManager.TryGetComponent<StatusEffectsComponent>(playerEntity, out var status))
|
||||
if (!_statusEffects.TryEffectsWithComp<DrowsinessStatusEffectComponent>(playerEntity, out var drowsinessEffects))
|
||||
return;
|
||||
|
||||
var statusSys = _sysMan.GetEntitySystem<StatusEffectsSystem>();
|
||||
if (!statusSys.TryGetTime(playerEntity.Value, SharedDrowsinessSystem.DrowsinessKey, out var time, status))
|
||||
TimeSpan? remainingTime = TimeSpan.Zero;
|
||||
foreach (var (_, _, statusEffectComp) in drowsinessEffects)
|
||||
{
|
||||
if (statusEffectComp.EndEffectTime > remainingTime)
|
||||
remainingTime = statusEffectComp.EndEffectTime;
|
||||
}
|
||||
|
||||
if (remainingTime is null)
|
||||
return;
|
||||
|
||||
var curTime = _timing.CurTime;
|
||||
var timeLeft = (float)(time.Value.Item2 - curTime).TotalSeconds;
|
||||
var timeLeft = (float)(remainingTime - curTime).Value.TotalSeconds;
|
||||
|
||||
CurrentPower += 8f * (0.5f * timeLeft - CurrentPower) * args.DeltaSeconds / (timeLeft + 1);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Content.Shared.Drowsiness;
|
||||
using Content.Shared.StatusEffectNew;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Client.Drowsiness;
|
||||
|
||||
@@ -9,6 +9,7 @@ public sealed class DrowsinessSystem : SharedDrowsinessSystem
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
[Dependency] private readonly IOverlayManager _overlayMan = default!;
|
||||
[Dependency] private readonly SharedStatusEffectsSystem _statusEffects = default!;
|
||||
|
||||
private DrowsinessOverlay _overlay = default!;
|
||||
|
||||
@@ -16,35 +17,47 @@ public sealed class DrowsinessSystem : SharedDrowsinessSystem
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DrowsinessComponent, ComponentInit>(OnDrowsinessInit);
|
||||
SubscribeLocalEvent<DrowsinessComponent, ComponentShutdown>(OnDrowsinessShutdown);
|
||||
SubscribeLocalEvent<DrowsinessStatusEffectComponent, StatusEffectAppliedEvent>(OnDrowsinessApply);
|
||||
SubscribeLocalEvent<DrowsinessStatusEffectComponent, StatusEffectRemovedEvent>(OnDrowsinessShutdown);
|
||||
|
||||
SubscribeLocalEvent<DrowsinessComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
|
||||
SubscribeLocalEvent<DrowsinessComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);
|
||||
SubscribeLocalEvent<DrowsinessStatusEffectComponent, StatusEffectPlayerAttachedEvent>(OnStatusEffectPlayerAttached);
|
||||
SubscribeLocalEvent<DrowsinessStatusEffectComponent, StatusEffectPlayerDetachedEvent>(OnStatusEffectPlayerDetached);
|
||||
|
||||
_overlay = new();
|
||||
}
|
||||
|
||||
private void OnPlayerAttached(EntityUid uid, DrowsinessComponent component, LocalPlayerAttachedEvent args)
|
||||
private void OnDrowsinessApply(Entity<DrowsinessStatusEffectComponent> ent, ref StatusEffectAppliedEvent args)
|
||||
{
|
||||
_overlayMan.AddOverlay(_overlay);
|
||||
}
|
||||
|
||||
private void OnPlayerDetached(EntityUid uid, DrowsinessComponent component, LocalPlayerDetachedEvent args)
|
||||
{
|
||||
_overlay.CurrentPower = 0;
|
||||
_overlayMan.RemoveOverlay(_overlay);
|
||||
}
|
||||
|
||||
private void OnDrowsinessInit(EntityUid uid, DrowsinessComponent component, ComponentInit args)
|
||||
{
|
||||
if (_player.LocalEntity == uid)
|
||||
if (_player.LocalEntity == args.Target)
|
||||
_overlayMan.AddOverlay(_overlay);
|
||||
}
|
||||
|
||||
private void OnDrowsinessShutdown(EntityUid uid, DrowsinessComponent component, ComponentShutdown args)
|
||||
private void OnDrowsinessShutdown(Entity<DrowsinessStatusEffectComponent> ent, ref StatusEffectRemovedEvent args)
|
||||
{
|
||||
if (_player.LocalEntity == uid)
|
||||
if (_player.LocalEntity != args.Target)
|
||||
return;
|
||||
|
||||
if (!_statusEffects.HasEffectComp<DrowsinessStatusEffectComponent>(_player.LocalEntity.Value))
|
||||
{
|
||||
_overlay.CurrentPower = 0;
|
||||
_overlayMan.RemoveOverlay(_overlay);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnStatusEffectPlayerAttached(Entity<DrowsinessStatusEffectComponent> ent, ref StatusEffectPlayerAttachedEvent args)
|
||||
{
|
||||
if (_player.LocalEntity != args.Target)
|
||||
return;
|
||||
|
||||
_overlayMan.AddOverlay(_overlay);
|
||||
}
|
||||
|
||||
private void OnStatusEffectPlayerDetached(Entity<DrowsinessStatusEffectComponent> ent, ref StatusEffectPlayerDetachedEvent args)
|
||||
{
|
||||
if (_player.LocalEntity != args.Target)
|
||||
return;
|
||||
|
||||
if (!_statusEffects.HasEffectComp<DrowsinessStatusEffectComponent>(_player.LocalEntity.Value))
|
||||
{
|
||||
_overlay.CurrentPower = 0;
|
||||
_overlayMan.RemoveOverlay(_overlay);
|
||||
|
||||
50
Content.Client/StatusEffectNew/ClientStatusEffectsSystem.cs
Normal file
50
Content.Client/StatusEffectNew/ClientStatusEffectsSystem.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using Content.Shared.StatusEffectNew;
|
||||
using Content.Shared.StatusEffectNew.Components;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Client.StatusEffectNew;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public sealed partial class ClientStatusEffectsSystem : SharedStatusEffectsSystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<StatusEffectContainerComponent, ComponentHandleState>(OnHandleState);
|
||||
}
|
||||
|
||||
private void OnHandleState(Entity<StatusEffectContainerComponent> ent, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not StatusEffectContainerComponentState state)
|
||||
return;
|
||||
|
||||
var toRemove = new ValueList<EntityUid>();
|
||||
foreach (var effect in ent.Comp.ActiveStatusEffects)
|
||||
{
|
||||
if (state.ActiveStatusEffects.Contains(GetNetEntity(effect)))
|
||||
continue;
|
||||
|
||||
toRemove.Add(effect);
|
||||
}
|
||||
|
||||
foreach (var effect in toRemove)
|
||||
{
|
||||
ent.Comp.ActiveStatusEffects.Remove(effect);
|
||||
var ev = new StatusEffectRemovedEvent(ent);
|
||||
RaiseLocalEvent(effect, ref ev);
|
||||
}
|
||||
|
||||
foreach (var effect in state.ActiveStatusEffects)
|
||||
{
|
||||
var effectUid = GetEntity(effect);
|
||||
if (ent.Comp.ActiveStatusEffects.Contains(effectUid))
|
||||
continue;
|
||||
|
||||
ent.Comp.ActiveStatusEffects.Add(effectUid);
|
||||
var ev = new StatusEffectAppliedEvent(ent);
|
||||
RaiseLocalEvent(effectUid, ref ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
using Content.Shared.Bed.Sleep;
|
||||
using Content.Server.StatusEffectNew;
|
||||
using Content.Shared.Bed.Sleep;
|
||||
using Content.Shared.Drowsiness;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Content.Shared.StatusEffectNew;
|
||||
using Content.Shared.StatusEffectNew.Components;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
@@ -8,9 +10,6 @@ namespace Content.Server.Drowsiness;
|
||||
|
||||
public sealed class DrowsinessSystem : SharedDrowsinessSystem
|
||||
{
|
||||
[ValidatePrototypeId<StatusEffectPrototype>]
|
||||
private const string SleepKey = "ForcedSleep"; // Same one used by N2O and other sleep chems.
|
||||
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
|
||||
@@ -18,33 +17,37 @@ public sealed class DrowsinessSystem : SharedDrowsinessSystem
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<DrowsinessComponent, ComponentStartup>(OnInit);
|
||||
SubscribeLocalEvent<DrowsinessStatusEffectComponent, StatusEffectAppliedEvent>(OnEffectApplied);
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, DrowsinessComponent component, ComponentStartup args)
|
||||
private void OnEffectApplied(Entity<DrowsinessStatusEffectComponent> ent, ref StatusEffectAppliedEvent args)
|
||||
{
|
||||
component.NextIncidentTime = _timing.CurTime + TimeSpan.FromSeconds(_random.NextFloat(component.TimeBetweenIncidents.X, component.TimeBetweenIncidents.Y));
|
||||
ent.Comp.NextIncidentTime = _timing.CurTime + TimeSpan.FromSeconds(_random.NextFloat(ent.Comp.TimeBetweenIncidents.X, ent.Comp.TimeBetweenIncidents.Y));
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<DrowsinessComponent>();
|
||||
while (query.MoveNext(out var uid, out var component))
|
||||
var query = EntityQueryEnumerator<DrowsinessStatusEffectComponent, StatusEffectComponent>();
|
||||
while (query.MoveNext(out var uid, out var drowsiness, out var statusEffect))
|
||||
{
|
||||
if (_timing.CurTime < component.NextIncidentTime)
|
||||
if (_timing.CurTime < drowsiness.NextIncidentTime)
|
||||
continue;
|
||||
|
||||
if (statusEffect.AppliedTo is null)
|
||||
continue;
|
||||
|
||||
// Set the new time.
|
||||
component.NextIncidentTime = _timing.CurTime + TimeSpan.FromSeconds(_random.NextFloat(component.TimeBetweenIncidents.X, component.TimeBetweenIncidents.Y));
|
||||
drowsiness.NextIncidentTime = _timing.CurTime + TimeSpan.FromSeconds(_random.NextFloat(drowsiness.TimeBetweenIncidents.X, drowsiness.TimeBetweenIncidents.Y));
|
||||
|
||||
// sleep duration
|
||||
var duration = TimeSpan.FromSeconds(_random.NextFloat(component.DurationOfIncident.X, component.DurationOfIncident.Y));
|
||||
var duration = TimeSpan.FromSeconds(_random.NextFloat(drowsiness.DurationOfIncident.X, drowsiness.DurationOfIncident.Y));
|
||||
|
||||
// Make sure the sleep time doesn't cut into the time to next incident.
|
||||
component.NextIncidentTime += duration;
|
||||
drowsiness.NextIncidentTime += duration;
|
||||
|
||||
_statusEffects.TryAddStatusEffect<ForcedSleepingComponent>(uid, SleepKey, duration, false);
|
||||
_statusEffects.TryAddStatusEffect(statusEffect.AppliedTo.Value, SleepingSystem.StatusEffectForcedSleeping, duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
23
Content.Server/StatusEffectNew/StatusEffectsSystem.cs
Normal file
23
Content.Server/StatusEffectNew/StatusEffectsSystem.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Content.Shared.StatusEffectNew;
|
||||
using Content.Shared.StatusEffectNew.Components;
|
||||
|
||||
namespace Content.Server.StatusEffectNew;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public sealed partial class StatusEffectsSystem : SharedStatusEffectsSystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<StatusEffectContainerComponent, ComponentShutdown>(OnContainerShutdown);
|
||||
}
|
||||
|
||||
private void OnContainerShutdown(Entity<StatusEffectContainerComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
foreach (var effect in ent.Comp.ActiveStatusEffects)
|
||||
{
|
||||
QueueDel(effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
using Content.Server.StatusEffectNew;
|
||||
using Content.Shared.Bed.Sleep;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.Traits.Assorted;
|
||||
@@ -9,9 +9,6 @@ namespace Content.Server.Traits.Assorted;
|
||||
/// </summary>
|
||||
public sealed class NarcolepsySystem : EntitySystem
|
||||
{
|
||||
[ValidatePrototypeId<StatusEffectPrototype>]
|
||||
private const string StatusEffectKey = "ForcedSleep"; // Same one used by N2O and other sleep chems.
|
||||
|
||||
[Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
@@ -56,8 +53,7 @@ public sealed class NarcolepsySystem : EntitySystem
|
||||
// Make sure the sleep time doesn't cut into the time to next incident.
|
||||
narcolepsy.NextIncidentTime += duration;
|
||||
|
||||
_statusEffects.TryAddStatusEffect<ForcedSleepingComponent>(uid, StatusEffectKey,
|
||||
TimeSpan.FromSeconds(duration), false);
|
||||
_statusEffects.TryAddStatusEffect(uid, SleepingSystem.StatusEffectForcedSleeping, TimeSpan.FromSeconds(duration));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Bed.Sleep
|
||||
{
|
||||
/// <summary>
|
||||
/// Prevents waking up. Use as a status effect.
|
||||
/// </summary>
|
||||
[NetworkedComponent, RegisterComponent]
|
||||
public sealed partial class ForcedSleepingComponent : Component
|
||||
{}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using Content.Shared.StatusEffectNew.Components;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Bed.Sleep;
|
||||
|
||||
/// <summary>
|
||||
/// Prevents waking up. Use only in conjunction with <see cref="StatusEffectComponent"/>, on the status effect entity.
|
||||
/// </summary>
|
||||
[NetworkedComponent, RegisterComponent]
|
||||
public sealed partial class ForcedSleepingStatusEffectComponent : Component;
|
||||
@@ -19,6 +19,7 @@ using Content.Shared.Sound;
|
||||
using Content.Shared.Sound.Components;
|
||||
using Content.Shared.Speech;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Content.Shared.StatusEffectNew;
|
||||
using Content.Shared.Stunnable;
|
||||
using Content.Shared.Traits.Assorted;
|
||||
using Content.Shared.Verbs;
|
||||
@@ -37,10 +38,12 @@ public sealed partial class SleepingSystem : EntitySystem
|
||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedEmitSoundSystem _emitSound = default!;
|
||||
[Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!;
|
||||
[Dependency] private readonly StatusEffectsSystem _statusEffectOld = default!;
|
||||
[Dependency] private readonly SharedStatusEffectsSystem _statusEffectNew = default!;
|
||||
|
||||
public static readonly EntProtoId SleepActionId = "ActionSleep";
|
||||
public static readonly EntProtoId WakeActionId = "ActionWake";
|
||||
public static readonly EntProtoId StatusEffectForcedSleeping = "StatusEffectForcedSleeping";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -65,7 +68,7 @@ public sealed partial class SleepingSystem : EntitySystem
|
||||
SubscribeLocalEvent<SleepingComponent, GetVerbsEvent<AlternativeVerb>>(AddWakeVerb);
|
||||
SubscribeLocalEvent<SleepingComponent, InteractHandEvent>(OnInteractHand);
|
||||
|
||||
SubscribeLocalEvent<ForcedSleepingComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<ForcedSleepingStatusEffectComponent, StatusEffectAppliedEvent>(OnStatusEffectApplied);
|
||||
SubscribeLocalEvent<SleepingComponent, UnbuckleAttemptEvent>(OnUnbuckleAttempt);
|
||||
SubscribeLocalEvent<SleepingComponent, EmoteAttemptEvent>(OnEmoteAttempt);
|
||||
|
||||
@@ -104,8 +107,8 @@ public sealed partial class SleepingSystem : EntitySystem
|
||||
if (args.FellAsleep)
|
||||
{
|
||||
// Expiring status effects would remove the components needed for sleeping
|
||||
_statusEffectsSystem.TryRemoveStatusEffect(ent.Owner, "Stun");
|
||||
_statusEffectsSystem.TryRemoveStatusEffect(ent.Owner, "KnockedDown");
|
||||
_statusEffectOld.TryRemoveStatusEffect(ent.Owner, "Stun");
|
||||
_statusEffectOld.TryRemoveStatusEffect(ent.Owner, "KnockedDown");
|
||||
|
||||
EnsureComp<StunnedComponent>(ent);
|
||||
EnsureComp<KnockedDownComponent>(ent);
|
||||
@@ -248,9 +251,9 @@ public sealed partial class SleepingSystem : EntitySystem
|
||||
_emitSound.SetEnabled((ent, spam), args.NewMobState == MobState.Alive);
|
||||
}
|
||||
|
||||
private void OnInit(Entity<ForcedSleepingComponent> ent, ref ComponentInit args)
|
||||
private void OnStatusEffectApplied(Entity<ForcedSleepingStatusEffectComponent> ent, ref StatusEffectAppliedEvent args)
|
||||
{
|
||||
TrySleeping(ent.Owner);
|
||||
TrySleeping(args.Target);
|
||||
}
|
||||
|
||||
private void Wake(Entity<SleepingComponent> ent)
|
||||
@@ -307,7 +310,7 @@ public sealed partial class SleepingSystem : EntitySystem
|
||||
if (!Resolve(ent, ref ent.Comp, false))
|
||||
return false;
|
||||
|
||||
if (!force && HasComp<ForcedSleepingComponent>(ent))
|
||||
if (!force && _statusEffectNew.HasEffectComp<ForcedSleepingStatusEffectComponent>(ent))
|
||||
{
|
||||
if (user != null)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ using Content.Shared.Damage.Events;
|
||||
using Content.Shared.Destructible;
|
||||
using Content.Shared.Rejuvenate;
|
||||
using Content.Shared.Slippery;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Content.Shared.StatusEffectNew;
|
||||
|
||||
namespace Content.Shared.Damage.Systems;
|
||||
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
using System.Numerics;
|
||||
using Content.Shared.StatusEffectNew.Components;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
|
||||
namespace Content.Shared.Drowsiness;
|
||||
|
||||
/// <summary>
|
||||
/// Exists for use as a status effect. Adds a shader to the client that scales with the effect duration.
|
||||
/// Exists for use as a status effect. Adds a shader to the client that scales with the effect duration.
|
||||
/// Use only in conjunction with <see cref="StatusEffectComponent"/>, on the status effect entity.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause]
|
||||
public sealed partial class DrowsinessComponent : Component
|
||||
public sealed partial class DrowsinessStatusEffectComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The random time between sleeping incidents, (min, max).
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public Vector2 TimeBetweenIncidents = new Vector2(5f, 60f);
|
||||
[DataField]
|
||||
public Vector2 TimeBetweenIncidents = new(5f, 60f);
|
||||
|
||||
/// <summary>
|
||||
/// The duration of sleeping incidents, (min, max).
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public Vector2 DurationOfIncident = new Vector2(2, 5);
|
||||
[DataField]
|
||||
public Vector2 DurationOfIncident = new(2, 5);
|
||||
|
||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
||||
[AutoPausedField]
|
||||
@@ -1,9 +1,5 @@
|
||||
using Content.Shared.StatusEffect;
|
||||
|
||||
namespace Content.Shared.Drowsiness;
|
||||
|
||||
public abstract class SharedDrowsinessSystem : EntitySystem
|
||||
{
|
||||
[ValidatePrototypeId<StatusEffectPrototype>]
|
||||
public const string DrowsinessKey = "Drowsiness";
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace Content.Shared.EntityEffects.Effects.StatusEffects;
|
||||
/// <remarks>
|
||||
/// Can be used for things like adding accents or something. I don't know. Go wild.
|
||||
/// </remarks>
|
||||
[Obsolete("Use ModifyStatusEffect with StatusEffectNewSystem instead")]
|
||||
public sealed partial class GenericStatusEffect : EntityEffect
|
||||
{
|
||||
[DataField(required: true)]
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
using Content.Shared.StatusEffectNew;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.EntityEffects.Effects.StatusEffects;
|
||||
|
||||
/// <summary>
|
||||
/// Changes status effects on entities: Adds, removes or sets time.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed partial class ModifyStatusEffect : EntityEffect
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public EntProtoId EffectProto;
|
||||
|
||||
/// <summary>
|
||||
/// Time for which status effect should be applied. Behaviour changes according to <see cref="Refresh" />.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float Time = 2.0f;
|
||||
|
||||
/// <remarks>
|
||||
/// true - refresh status effect time, false - accumulate status effect time.
|
||||
/// </remarks>
|
||||
[DataField]
|
||||
public bool Refresh = true;
|
||||
|
||||
/// <summary>
|
||||
/// Should this effect add the status effect, remove time from it, or set its cooldown?
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public StatusEffectMetabolismType Type = StatusEffectMetabolismType.Add;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
var statusSys = args.EntityManager.EntitySysManager.GetEntitySystem<SharedStatusEffectsSystem>();
|
||||
|
||||
var time = Time;
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
time *= reagentArgs.Scale.Float();
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case StatusEffectMetabolismType.Add:
|
||||
statusSys.TryAddStatusEffect(args.TargetEntity, EffectProto, TimeSpan.FromSeconds(time), Refresh);
|
||||
break;
|
||||
case StatusEffectMetabolismType.Remove:
|
||||
statusSys.TryAddTime(args.TargetEntity, EffectProto, -TimeSpan.FromSeconds(time));
|
||||
break;
|
||||
case StatusEffectMetabolismType.Set:
|
||||
statusSys.TrySetTime(args.TargetEntity, EffectProto, TimeSpan.FromSeconds(time));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString(
|
||||
"reagent-effect-guidebook-status-effect",
|
||||
("chance", Probability),
|
||||
("type", Type),
|
||||
("time", Time),
|
||||
("key", prototype.Index(EffectProto).Name)
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Shared.Bed.Sleep;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.StatusEffectNew;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Timing;
|
||||
@@ -13,6 +14,7 @@ public sealed class SSDIndicatorSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly SharedStatusEffectsSystem _statusEffects = default!;
|
||||
|
||||
private bool _icSsdSleep;
|
||||
private float _icSsdSleepTime;
|
||||
@@ -37,10 +39,11 @@ public sealed class SSDIndicatorSystem : EntitySystem
|
||||
component.FallAsleepTime = TimeSpan.Zero;
|
||||
if (component.ForcedSleepAdded) // Remove component only if it has been added by this system
|
||||
{
|
||||
EntityManager.RemoveComponent<ForcedSleepingComponent>(uid);
|
||||
_statusEffects.TryRemoveStatusEffect(uid, SleepingSystem.StatusEffectForcedSleeping);
|
||||
component.ForcedSleepAdded = false;
|
||||
}
|
||||
}
|
||||
|
||||
Dirty(uid, component);
|
||||
}
|
||||
|
||||
@@ -53,6 +56,7 @@ public sealed class SSDIndicatorSystem : EntitySystem
|
||||
{
|
||||
component.FallAsleepTime = _timing.CurTime + TimeSpan.FromSeconds(_icSsdSleepTime);
|
||||
}
|
||||
|
||||
Dirty(uid, component);
|
||||
}
|
||||
|
||||
@@ -79,12 +83,11 @@ public sealed class SSDIndicatorSystem : EntitySystem
|
||||
while (query.MoveNext(out var uid, out var ssd))
|
||||
{
|
||||
// Forces the entity to sleep when the time has come
|
||||
if(ssd.IsSSD &&
|
||||
if (ssd.IsSSD &&
|
||||
ssd.FallAsleepTime <= _timing.CurTime &&
|
||||
!TerminatingOrDeleted(uid) &&
|
||||
!HasComp<ForcedSleepingComponent>(uid)) // Don't add the component if the entity has it from another sources
|
||||
!TerminatingOrDeleted(uid))
|
||||
{
|
||||
EnsureComp<ForcedSleepingComponent>(uid);
|
||||
_statusEffects.TryAddStatusEffect(uid, SleepingSystem.StatusEffectForcedSleeping);
|
||||
ssd.ForcedSleepAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Rejuvenate;
|
||||
using Content.Shared.StatusEffectNew;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
@@ -8,6 +9,7 @@ using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.StatusEffect
|
||||
{
|
||||
[Obsolete("Migration to Content.Shared.StatusEffectNew.SharedStatusEffectsSystem is required")]
|
||||
public sealed class StatusEffectsSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
@@ -104,6 +106,7 @@ namespace Content.Shared.StatusEffect
|
||||
/// <param name="status">The status effects component to change, if you already have it.</param>
|
||||
/// <returns>False if the effect could not be added or the component already exists, true otherwise.</returns>
|
||||
/// <typeparam name="T">The component type to add and remove from the entity.</typeparam>
|
||||
[Obsolete("Migration to Content.Shared.StatusEffectNew.SharedStatusEffectsSystem is required")]
|
||||
public bool TryAddStatusEffect<T>(EntityUid uid, string key, TimeSpan time, bool refresh,
|
||||
StatusEffectsComponent? status = null)
|
||||
where T : IComponent, new()
|
||||
@@ -123,6 +126,7 @@ namespace Content.Shared.StatusEffect
|
||||
|
||||
}
|
||||
|
||||
[Obsolete("Migration to Content.Shared.StatusEffectNew.SharedStatusEffectsSystem is required")]
|
||||
public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool refresh, string component,
|
||||
StatusEffectsComponent? status = null)
|
||||
{
|
||||
@@ -162,6 +166,7 @@ namespace Content.Shared.StatusEffect
|
||||
/// If the effect already exists, it will simply replace the cooldown with the new one given.
|
||||
/// If you want special 'effect merging' behavior, do it your own damn self!
|
||||
/// </remarks>
|
||||
[Obsolete("Migration to Content.Shared.StatusEffectNew.SharedStatusEffectsSystem is required")]
|
||||
public bool TryAddStatusEffect(EntityUid uid,
|
||||
string key,
|
||||
TimeSpan time,
|
||||
@@ -255,6 +260,7 @@ namespace Content.Shared.StatusEffect
|
||||
/// Obviously this doesn't automatically clear any effects a status effect might have.
|
||||
/// That's up to the removed component to handle itself when it's removed.
|
||||
/// </remarks>
|
||||
[Obsolete("Migration to Content.Shared.StatusEffectNew.SharedStatusEffectsSystem is required")]
|
||||
public bool TryRemoveStatusEffect(EntityUid uid, string key,
|
||||
StatusEffectsComponent? status = null, bool remComp = true)
|
||||
{
|
||||
@@ -298,6 +304,7 @@ namespace Content.Shared.StatusEffect
|
||||
/// <param name="uid">The entity to remove effects from.</param>
|
||||
/// <param name="status">The status effects component to change, if you already have it.</param>
|
||||
/// <returns>False if any status effects failed to be removed, true if they all did.</returns>
|
||||
[Obsolete("Migration to Content.Shared.StatusEffectNew.SharedStatusEffectsSystem is required")]
|
||||
public bool TryRemoveAllStatusEffects(EntityUid uid,
|
||||
StatusEffectsComponent? status = null)
|
||||
{
|
||||
@@ -321,6 +328,7 @@ namespace Content.Shared.StatusEffect
|
||||
/// <param name="uid">The entity to check on.</param>
|
||||
/// <param name="key">The status effect ID to check for</param>
|
||||
/// <param name="status">The status effect component, should you already have it.</param>
|
||||
[Obsolete("Migration to Content.Shared.StatusEffectNew.SharedStatusEffectsSystem is required")]
|
||||
public bool HasStatusEffect(EntityUid uid, string key,
|
||||
StatusEffectsComponent? status = null)
|
||||
{
|
||||
@@ -338,6 +346,7 @@ namespace Content.Shared.StatusEffect
|
||||
/// <param name="uid">The entity to check on.</param>
|
||||
/// <param name="key">The status effect ID to check for</param>
|
||||
/// <param name="status">The status effect component, should you already have it.</param>
|
||||
[Obsolete("Migration to Content.Shared.StatusEffectNew.SharedStatusEffectsSystem is required")]
|
||||
public bool CanApplyEffect(EntityUid uid, string key, StatusEffectsComponent? status = null)
|
||||
{
|
||||
// don't log since stuff calling this prolly doesn't care if we don't actually have it
|
||||
@@ -364,6 +373,7 @@ namespace Content.Shared.StatusEffect
|
||||
/// <param name="key">The status effect to add time to.</param>
|
||||
/// <param name="time">The amount of time to add.</param>
|
||||
/// <param name="status">The status effect component, should you already have it.</param>
|
||||
[Obsolete("Migration to Content.Shared.StatusEffectNew.SharedStatusEffectsSystem is required")]
|
||||
public bool TryAddTime(EntityUid uid, string key, TimeSpan time,
|
||||
StatusEffectsComponent? status = null)
|
||||
{
|
||||
@@ -395,6 +405,7 @@ namespace Content.Shared.StatusEffect
|
||||
/// <param name="key">The status effect to remove time from.</param>
|
||||
/// <param name="time">The amount of time to add.</param>
|
||||
/// <param name="status">The status effect component, should you already have it.</param>
|
||||
[Obsolete("Migration to Content.Shared.StatusEffectNew.SharedStatusEffectsSystem is required")]
|
||||
public bool TryRemoveTime(EntityUid uid, string key, TimeSpan time,
|
||||
StatusEffectsComponent? status = null)
|
||||
{
|
||||
@@ -430,6 +441,7 @@ namespace Content.Shared.StatusEffect
|
||||
/// <remarks>
|
||||
/// Not used internally; just sets it itself.
|
||||
/// </remarks>
|
||||
[Obsolete("Migration to Content.Shared.StatusEffectNew.SharedStatusEffectsSystem is required")]
|
||||
public bool TrySetTime(EntityUid uid, string key, TimeSpan time,
|
||||
StatusEffectsComponent? status = null)
|
||||
{
|
||||
@@ -453,6 +465,7 @@ namespace Content.Shared.StatusEffect
|
||||
/// <param name="time">Out var for the time, if it exists.</param>
|
||||
/// <param name="status">The status effects component to use, if any.</param>
|
||||
/// <returns>False if the status effect was not active, true otherwise.</returns>
|
||||
[Obsolete("Migration to Content.Shared.StatusEffectNew.SharedStatusEffectsSystem is required")]
|
||||
public bool TryGetTime(EntityUid uid, string key,
|
||||
[NotNullWhen(true)] out (TimeSpan, TimeSpan)? time,
|
||||
StatusEffectsComponent? status = null)
|
||||
@@ -468,12 +481,6 @@ namespace Content.Shared.StatusEffect
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised on an entity before a status effect is added to determine if adding it should be cancelled.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct BeforeStatusEffectAddedEvent(string Key, bool Cancelled=false);
|
||||
|
||||
public readonly struct StatusEffectAddedEvent
|
||||
{
|
||||
public readonly EntityUid Uid;
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
|
||||
namespace Content.Shared.StatusEffectNew.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Marker component for all status effects - every status effect entity should have it.
|
||||
/// Provides a link between the effect and the affected entity, and some data common to all status effects.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause]
|
||||
[Access(typeof(SharedStatusEffectsSystem))]
|
||||
[EntityCategory("StatusEffects")]
|
||||
public sealed partial class StatusEffectComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The entity that this status effect is applied to.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public EntityUid? AppliedTo;
|
||||
|
||||
/// <summary>
|
||||
/// Status effect indication for the player. If Null, no Alert will be displayed.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ProtoId<AlertPrototype>? Alert;
|
||||
|
||||
/// <summary>
|
||||
/// When this effect will end. If Null, the effect lasts indefinitely.
|
||||
/// </summary>
|
||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField, AutoNetworkedField]
|
||||
public TimeSpan? EndEffectTime;
|
||||
|
||||
/// <summary>
|
||||
/// Whitelist, by which it is determined whether this status effect can be imposed on a particular entity.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntityWhitelist? Whitelist;
|
||||
|
||||
/// <summary>
|
||||
/// Blacklist, by which it is determined whether this status effect can be imposed on a particular entity.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntityWhitelist? Blacklist;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.StatusEffectNew.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Adds container for status effect entities that are applied to entity.
|
||||
/// Is applied automatically upon adding any status effect.
|
||||
/// Can be used for tracking currently applied status effects.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
[Access(typeof(SharedStatusEffectsSystem))]
|
||||
public sealed partial class StatusEffectContainerComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public HashSet<EntityUid> ActiveStatusEffects = new();
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class StatusEffectContainerComponentState(HashSet<NetEntity> activeStatusEffects) : ComponentState
|
||||
{
|
||||
public readonly HashSet<NetEntity> ActiveStatusEffects = activeStatusEffects;
|
||||
}
|
||||
208
Content.Shared/StatusEffectNew/SharedStatusEffectsSystem.cs
Normal file
208
Content.Shared/StatusEffectNew/SharedStatusEffectsSystem.cs
Normal file
@@ -0,0 +1,208 @@
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.StatusEffectNew.Components;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Shared.StatusEffectNew;
|
||||
|
||||
/// <summary>
|
||||
/// This system controls status effects, their lifetime, and provides an API for adding them to entities,
|
||||
/// removing them from entities, or getting information about current effects on entities.
|
||||
/// </summary>
|
||||
public abstract partial class SharedStatusEffectsSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AlertsSystem _alerts = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly IComponentFactory _compFactory = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
|
||||
private EntityQuery<StatusEffectContainerComponent> _containerQuery;
|
||||
private EntityQuery<StatusEffectComponent> _effectQuery;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<StatusEffectComponent, StatusEffectAppliedEvent>(OnStatusEffectApplied);
|
||||
SubscribeLocalEvent<StatusEffectComponent, StatusEffectRemovedEvent>(OnStatusEffectRemoved);
|
||||
|
||||
SubscribeLocalEvent<StatusEffectContainerComponent, LocalPlayerAttachedEvent>(OnStatusEffectContainerAttached);
|
||||
SubscribeLocalEvent<StatusEffectContainerComponent, LocalPlayerDetachedEvent>(OnStatusEffectContainerDetached);
|
||||
SubscribeLocalEvent<StatusEffectContainerComponent, ComponentGetState>(OnGetState);
|
||||
|
||||
_containerQuery = GetEntityQuery<StatusEffectContainerComponent>();
|
||||
_effectQuery = GetEntityQuery<StatusEffectComponent>();
|
||||
}
|
||||
|
||||
private void OnGetState(Entity<StatusEffectContainerComponent> ent, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new StatusEffectContainerComponentState(GetNetEntitySet(ent.Comp.ActiveStatusEffects));
|
||||
}
|
||||
|
||||
private void OnStatusEffectContainerAttached(Entity<StatusEffectContainerComponent> ent, ref LocalPlayerAttachedEvent args)
|
||||
{
|
||||
foreach (var effect in ent.Comp.ActiveStatusEffects)
|
||||
{
|
||||
var ev = new StatusEffectPlayerAttachedEvent(ent);
|
||||
RaiseLocalEvent(effect, ref ev);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnStatusEffectContainerDetached(Entity<StatusEffectContainerComponent> ent, ref LocalPlayerDetachedEvent args)
|
||||
{
|
||||
foreach (var effect in ent.Comp.ActiveStatusEffects)
|
||||
{
|
||||
var ev = new StatusEffectPlayerDetachedEvent(ent);
|
||||
RaiseLocalEvent(effect, ref ev);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<StatusEffectComponent>();
|
||||
while (query.MoveNext(out var ent, out var effect))
|
||||
{
|
||||
if (effect.EndEffectTime is null)
|
||||
continue;
|
||||
|
||||
if (!(_timing.CurTime >= effect.EndEffectTime))
|
||||
continue;
|
||||
|
||||
if (effect.AppliedTo is null)
|
||||
continue;
|
||||
|
||||
var meta = MetaData(ent);
|
||||
if (meta.EntityPrototype is null)
|
||||
continue;
|
||||
|
||||
TryRemoveStatusEffect(effect.AppliedTo.Value, meta.EntityPrototype);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddStatusEffectTime(EntityUid effect, TimeSpan delta)
|
||||
{
|
||||
if (!_effectQuery.TryComp(effect, out var effectComp))
|
||||
return;
|
||||
|
||||
effectComp.EndEffectTime += delta;
|
||||
Dirty(effect, effectComp);
|
||||
|
||||
if (effectComp is { AppliedTo: not null, Alert: not null })
|
||||
{
|
||||
(TimeSpan Start, TimeSpan End)? cooldown = effectComp.EndEffectTime is null
|
||||
? null
|
||||
: (_timing.CurTime, effectComp.EndEffectTime.Value);
|
||||
_alerts.ShowAlert(
|
||||
effectComp.AppliedTo.Value,
|
||||
effectComp.Alert.Value,
|
||||
cooldown: cooldown
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetStatusEffectTime(EntityUid effect, TimeSpan duration)
|
||||
{
|
||||
if (!_effectQuery.TryComp(effect, out var effectComp))
|
||||
return;
|
||||
|
||||
effectComp.EndEffectTime = _timing.CurTime + duration;
|
||||
Dirty(effect, effectComp);
|
||||
|
||||
if (effectComp is { AppliedTo: not null, Alert: not null })
|
||||
{
|
||||
(TimeSpan, TimeSpan)? cooldown = effectComp.EndEffectTime is null
|
||||
? null
|
||||
: (_timing.CurTime, effectComp.EndEffectTime.Value);
|
||||
_alerts.ShowAlert(
|
||||
effectComp.AppliedTo.Value,
|
||||
effectComp.Alert.Value,
|
||||
cooldown: cooldown
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnStatusEffectApplied(Entity<StatusEffectComponent> ent, ref StatusEffectAppliedEvent args)
|
||||
{
|
||||
if (ent.Comp is { AppliedTo: not null, Alert: not null })
|
||||
{
|
||||
(TimeSpan, TimeSpan)? cooldown = ent.Comp.EndEffectTime is null
|
||||
? null
|
||||
: (_timing.CurTime, ent.Comp.EndEffectTime.Value);
|
||||
_alerts.ShowAlert(
|
||||
ent.Comp.AppliedTo.Value,
|
||||
ent.Comp.Alert.Value,
|
||||
cooldown: cooldown
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnStatusEffectRemoved(Entity<StatusEffectComponent> ent, ref StatusEffectRemovedEvent args)
|
||||
{
|
||||
if (ent.Comp.AppliedTo is null)
|
||||
return;
|
||||
|
||||
if (ent.Comp is { AppliedTo: not null, Alert: not null })
|
||||
_alerts.ClearAlert(ent.Comp.AppliedTo.Value, ent.Comp.Alert.Value);
|
||||
}
|
||||
|
||||
private bool CanAddStatusEffect(EntityUid uid, EntProtoId effectProto)
|
||||
{
|
||||
if (!_proto.TryIndex(effectProto, out var effectProtoData))
|
||||
return false;
|
||||
|
||||
if (!effectProtoData.TryGetComponent<StatusEffectComponent>(out var effectProtoComp, _compFactory))
|
||||
return false;
|
||||
|
||||
if (!_whitelist.CheckBoth(uid, effectProtoComp.Blacklist, effectProtoComp.Whitelist))
|
||||
return false;
|
||||
|
||||
var ev = new BeforeStatusEffectAddedEvent(effectProto);
|
||||
RaiseLocalEvent(uid, ref ev);
|
||||
|
||||
if (ev.Cancelled)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls on effect entity, when a status effect is applied.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public readonly record struct StatusEffectAppliedEvent(EntityUid Target);
|
||||
|
||||
/// <summary>
|
||||
/// Calls on effect entity, when a status effect is removed.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public readonly record struct StatusEffectRemovedEvent(EntityUid Target);
|
||||
|
||||
/// <summary>
|
||||
/// Called on a status effect entity inside <see cref="StatusEffectContainerComponent"/>
|
||||
/// after a player has been <see cref="LocalPlayerAttachedEvent"/> to this container entity.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public readonly record struct StatusEffectPlayerAttachedEvent(EntityUid Target);
|
||||
|
||||
/// <summary>
|
||||
/// Called on a status effect entity inside <see cref="StatusEffectContainerComponent"/>
|
||||
/// after a player has been <see cref="LocalPlayerDetachedEvent"/> to this container entity.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public readonly record struct StatusEffectPlayerDetachedEvent(EntityUid Target);
|
||||
|
||||
/// <summary>
|
||||
/// Raised on an entity before a status effect is added to determine if adding it should be cancelled.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct BeforeStatusEffectAddedEvent(EntProtoId Effect, bool Cancelled = false);
|
||||
265
Content.Shared/StatusEffectNew/StatusEffectNewSystem.API.cs
Normal file
265
Content.Shared/StatusEffectNew/StatusEffectNewSystem.API.cs
Normal file
@@ -0,0 +1,265 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Shared.StatusEffectNew.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.StatusEffectNew;
|
||||
|
||||
public abstract partial class SharedStatusEffectsSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Attempts to add a status effect to the specified entity. Returns True if the effect is added or it already exists
|
||||
/// and has been successfully extended in time, returns False if the status effect cannot be applied to this entity,
|
||||
/// or for any other reason.
|
||||
/// </summary>
|
||||
/// <param name="target">The target entity to which the effect should be added.</param>
|
||||
/// <param name="effectProto">ProtoId of the status effect entity. Make sure it has StatusEffectComponent on it.</param>
|
||||
/// <param name="duration">Duration of status effect. Leave null and the effect will be permanent until it is removed using <c>TryRemoveStatusEffect</c>.</param>
|
||||
/// <param name="resetCooldown">
|
||||
/// If True, the effect duration time will be reset and reapplied. If False, the effect duration time will be overlaid with the existing one.
|
||||
/// In the other case, the effect will either be added for the specified time or its time will be extended for the specified time.
|
||||
/// </param>
|
||||
public bool TryAddStatusEffect(
|
||||
EntityUid target,
|
||||
EntProtoId effectProto,
|
||||
TimeSpan? duration = null,
|
||||
bool resetCooldown = false
|
||||
)
|
||||
{
|
||||
if (TryGetStatusEffect(target, effectProto, out var existedEffect))
|
||||
{
|
||||
//We don't need to add the effect if it already exists
|
||||
if (duration is null)
|
||||
return true;
|
||||
|
||||
if (resetCooldown)
|
||||
SetStatusEffectTime(existedEffect.Value, duration.Value);
|
||||
else
|
||||
AddStatusEffectTime(existedEffect.Value, duration.Value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!CanAddStatusEffect(target, effectProto))
|
||||
return false;
|
||||
|
||||
var container = EnsureComp<StatusEffectContainerComponent>(target);
|
||||
|
||||
//And only if all checks passed we spawn the effect
|
||||
var effect = PredictedSpawnAttachedTo(effectProto, Transform(target).Coordinates);
|
||||
_transform.SetParent(effect, target);
|
||||
if (!_effectQuery.TryComp(effect, out var effectComp))
|
||||
return false;
|
||||
|
||||
if (duration != null)
|
||||
effectComp.EndEffectTime = _timing.CurTime + duration;
|
||||
|
||||
container.ActiveStatusEffects.Add(effect);
|
||||
effectComp.AppliedTo = target;
|
||||
Dirty(target, container);
|
||||
Dirty(effect, effectComp);
|
||||
|
||||
var ev = new StatusEffectAppliedEvent(target);
|
||||
RaiseLocalEvent(effect, ref ev);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempting to remove a status effect from an entity.
|
||||
/// Returns True if the status effect existed on the entity and was successfully removed, and False in otherwise.
|
||||
/// </summary>
|
||||
public bool TryRemoveStatusEffect(EntityUid target, EntProtoId effectProto)
|
||||
{
|
||||
if (_net.IsClient) //We cant remove the effect on the client (we need someone more robust at networking than me)
|
||||
return false;
|
||||
|
||||
if (!_containerQuery.TryComp(target, out var container))
|
||||
return false;
|
||||
|
||||
foreach (var effect in container.ActiveStatusEffects)
|
||||
{
|
||||
var meta = MetaData(effect);
|
||||
if (meta.EntityPrototype is not null && meta.EntityPrototype == effectProto)
|
||||
{
|
||||
if (!_effectQuery.TryComp(effect, out var effectComp))
|
||||
return false;
|
||||
|
||||
var ev = new StatusEffectRemovedEvent(target);
|
||||
RaiseLocalEvent(effect, ref ev);
|
||||
|
||||
QueueDel(effect);
|
||||
container.ActiveStatusEffects.Remove(effect);
|
||||
Dirty(target, container);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the specified entity is under a specific status effect.
|
||||
/// </summary>
|
||||
public bool HasStatusEffect(EntityUid target, EntProtoId effectProto)
|
||||
{
|
||||
if (!_containerQuery.TryComp(target, out var container))
|
||||
return false;
|
||||
|
||||
foreach (var effect in container.ActiveStatusEffects)
|
||||
{
|
||||
var meta = MetaData(effect);
|
||||
if (meta.EntityPrototype is not null && meta.EntityPrototype == effectProto)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempting to retrieve the EntityUid of a status effect from an entity.
|
||||
/// </summary>
|
||||
public bool TryGetStatusEffect(EntityUid target, EntProtoId effectProto, [NotNullWhen(true)] out EntityUid? effect)
|
||||
{
|
||||
effect = null;
|
||||
if (!_containerQuery.TryComp(target, out var container))
|
||||
return false;
|
||||
|
||||
foreach (var e in container.ActiveStatusEffects)
|
||||
{
|
||||
var meta = MetaData(e);
|
||||
if (meta.EntityPrototype is not null && meta.EntityPrototype == effectProto)
|
||||
{
|
||||
effect = e;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempting to retrieve the time of a status effect from an entity.
|
||||
/// </summary>
|
||||
/// <param name="uid">The target entity on which the effect is applied.</param>
|
||||
/// <param name="effectProto">The prototype ID of the status effect to retrieve.</param>
|
||||
/// <param name="time">The output tuple containing the effect entity and its remaining time.</param>
|
||||
/// <param name="container">Optional. The status effect container component of the entity.</param>
|
||||
public bool TryGetTime(
|
||||
EntityUid uid,
|
||||
EntProtoId effectProto,
|
||||
out (EntityUid EffectEnt, TimeSpan? EndEffectTime) time,
|
||||
StatusEffectContainerComponent? container = null
|
||||
)
|
||||
{
|
||||
time = default;
|
||||
if (!Resolve(uid, ref container))
|
||||
return false;
|
||||
|
||||
foreach (var effect in container.ActiveStatusEffects)
|
||||
{
|
||||
var meta = MetaData(effect);
|
||||
if (meta.EntityPrototype is not null && meta.EntityPrototype == effectProto)
|
||||
{
|
||||
if (!_effectQuery.TryComp(effect, out var effectComp))
|
||||
return false;
|
||||
|
||||
time = (effect, effectComp.EndEffectTime);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to edit the remaining time for a status effect on an entity.
|
||||
/// </summary>
|
||||
/// <param name="uid">The target entity on which the effect is applied.</param>
|
||||
/// <param name="effectProto">The prototype ID of the status effect to modify.</param>
|
||||
/// <param name="time">
|
||||
/// The time adjustment to apply to the status effect. Positive values extend the duration,
|
||||
/// while negative values reduce it.
|
||||
/// </param>
|
||||
/// <returns> True if duration was edited successfully, false otherwise.</returns>
|
||||
public bool TryAddTime(EntityUid uid, EntProtoId effectProto, TimeSpan time)
|
||||
{
|
||||
if (!_containerQuery.TryComp(uid, out var container))
|
||||
return false;
|
||||
|
||||
foreach (var effect in container.ActiveStatusEffects)
|
||||
{
|
||||
var meta = MetaData(effect);
|
||||
if (meta.EntityPrototype is not null && meta.EntityPrototype == effectProto)
|
||||
{
|
||||
AddStatusEffectTime(effect, time);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to set the remaining time for a status effect on an entity.
|
||||
/// </summary>
|
||||
/// <param name="uid">The target entity on which the effect is applied.</param>
|
||||
/// <param name="effectProto">The prototype ID of the status effect to modify.</param>
|
||||
/// <param name="time">The new duration for the status effect.</param>
|
||||
/// <returns> True if duration was set successfully, false otherwise.</returns>
|
||||
public bool TrySetTime(EntityUid uid, EntProtoId effectProto, TimeSpan time)
|
||||
{
|
||||
if (!_containerQuery.TryComp(uid, out var container))
|
||||
return false;
|
||||
|
||||
foreach (var effect in container.ActiveStatusEffects)
|
||||
{
|
||||
var meta = MetaData(effect);
|
||||
if (meta.EntityPrototype is not null && meta.EntityPrototype == effectProto)
|
||||
{
|
||||
SetStatusEffectTime(effect, time);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the specified component is present on any of the entity's status effects.
|
||||
/// </summary>
|
||||
public bool HasEffectComp<T>(EntityUid? target) where T : IComponent
|
||||
{
|
||||
if (!_containerQuery.TryComp(target, out var container))
|
||||
return false;
|
||||
|
||||
foreach (var effect in container.ActiveStatusEffects)
|
||||
{
|
||||
if (HasComp<T>(effect))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all status effects that have the specified component.
|
||||
/// </summary>
|
||||
public bool TryEffectsWithComp<T>(EntityUid? target, [NotNullWhen(true)] out HashSet<Entity<T, StatusEffectComponent>>? effects) where T : IComponent
|
||||
{
|
||||
effects = null;
|
||||
if (!_containerQuery.TryComp(target, out var container))
|
||||
return false;
|
||||
|
||||
foreach (var effect in container.ActiveStatusEffects)
|
||||
{
|
||||
if (!TryComp<StatusEffectComponent>(effect, out var statusComp))
|
||||
continue;
|
||||
|
||||
if (TryComp<T>(effect, out var comp))
|
||||
{
|
||||
effects ??= [];
|
||||
effects.Add((effect, comp, statusComp));
|
||||
}
|
||||
}
|
||||
|
||||
return effects != null;
|
||||
}
|
||||
}
|
||||
@@ -4,5 +4,6 @@ entity-category-name-objectives = Objectives
|
||||
entity-category-name-roles = Mind Roles
|
||||
entity-category-name-mapping = Mapping
|
||||
entity-category-name-donotmap = Do not map
|
||||
entity-category-name-status-effects = Status Effects
|
||||
|
||||
entity-category-suffix-donotmap = DO NOT MAP
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
- Electrocution
|
||||
- TemporaryBlindness
|
||||
- RadiationProtection
|
||||
- Drowsiness
|
||||
- Adrenaline
|
||||
- type: StandingState
|
||||
- type: Tag
|
||||
|
||||
@@ -22,12 +22,10 @@
|
||||
- SlowedDown
|
||||
- Stutter
|
||||
- Electrocution
|
||||
- ForcedSleep
|
||||
- TemporaryBlindness
|
||||
- Pacified
|
||||
- Flashed
|
||||
- RadiationProtection
|
||||
- Drowsiness
|
||||
- Adrenaline
|
||||
- type: Buckle
|
||||
- type: StandingState
|
||||
@@ -100,13 +98,11 @@
|
||||
- SlowedDown
|
||||
- Stutter
|
||||
- Electrocution
|
||||
- ForcedSleep
|
||||
- TemporaryBlindness
|
||||
- Pacified
|
||||
- StaminaModifier
|
||||
- Flashed
|
||||
- RadiationProtection
|
||||
- Drowsiness
|
||||
- Adrenaline
|
||||
- type: Bloodstream
|
||||
bloodMaxVolume: 150
|
||||
|
||||
@@ -103,11 +103,9 @@
|
||||
- SlowedDown
|
||||
- Stutter
|
||||
- Electrocution
|
||||
- ForcedSleep
|
||||
- TemporaryBlindness
|
||||
- Pacified
|
||||
- RadiationProtection
|
||||
- Drowsiness
|
||||
- Adrenaline
|
||||
- type: Temperature
|
||||
heatDamageThreshold: 800
|
||||
|
||||
@@ -130,13 +130,11 @@
|
||||
- RatvarianLanguage
|
||||
- PressureImmunity
|
||||
- Muted
|
||||
- ForcedSleep
|
||||
- TemporaryBlindness
|
||||
- Pacified
|
||||
- StaminaModifier
|
||||
- Flashed
|
||||
- RadiationProtection
|
||||
- Drowsiness
|
||||
- Adrenaline
|
||||
- type: Body
|
||||
prototype: Human
|
||||
|
||||
36
Resources/Prototypes/Entities/StatusEffects/misc.yml
Normal file
36
Resources/Prototypes/Entities/StatusEffects/misc.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
- type: entity
|
||||
id: StatusEffectBase
|
||||
abstract: true
|
||||
components:
|
||||
- type: StatusEffect
|
||||
- type: Sprite
|
||||
drawdepth: Effects
|
||||
- type: Tag
|
||||
tags:
|
||||
- HideContextMenu
|
||||
|
||||
- type: entity
|
||||
parent: StatusEffectBase
|
||||
id: MobStatusEffectBase
|
||||
abstract: true
|
||||
components:
|
||||
- type: StatusEffect
|
||||
whitelist:
|
||||
components:
|
||||
- MobState
|
||||
|
||||
# The creature sleeps so heavily that nothing can wake him up. Not even its own death.
|
||||
- type: entity
|
||||
parent: MobStatusEffectBase
|
||||
id: StatusEffectForcedSleeping
|
||||
name: forced sleep
|
||||
components:
|
||||
- type: ForcedSleepingStatusEffect
|
||||
|
||||
# Blurs your vision and makes you randomly fall asleep
|
||||
- type: entity
|
||||
parent: MobStatusEffectBase
|
||||
id: StatusEffectDrowsiness
|
||||
name: drowsiness
|
||||
components:
|
||||
- type: DrowsinessStatusEffect
|
||||
@@ -27,3 +27,8 @@
|
||||
id: DoNotMap
|
||||
name: entity-category-name-donotmap
|
||||
suffix: entity-category-suffix-donotmap
|
||||
|
||||
- type: entityCategory
|
||||
id: StatusEffects
|
||||
name: entity-category-name-status-effects
|
||||
hideSpawnMenu: true
|
||||
@@ -2018,9 +2018,9 @@
|
||||
- !type:AdjustReagent
|
||||
reagent: Theobromine
|
||||
amount: 0.05
|
||||
- !type:GenericStatusEffect
|
||||
key: Drowsiness
|
||||
time: 1.0
|
||||
- !type:ModifyStatusEffect
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 1
|
||||
type: Remove
|
||||
fizziness: 0.25
|
||||
|
||||
@@ -2049,9 +2049,9 @@
|
||||
- !type:AdjustReagent
|
||||
reagent: Theobromine
|
||||
amount: 0.05
|
||||
- !type:GenericStatusEffect
|
||||
key: Drowsiness
|
||||
time: 1.0
|
||||
- !type:ModifyStatusEffect
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 1
|
||||
type: Remove
|
||||
fizziness: 0.15
|
||||
|
||||
@@ -2080,9 +2080,9 @@
|
||||
- !type:AdjustReagent
|
||||
reagent: Theobromine
|
||||
amount: 0.05
|
||||
- !type:GenericStatusEffect
|
||||
key: Drowsiness
|
||||
time: 1.0
|
||||
- !type:ModifyStatusEffect
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 1
|
||||
type: Remove
|
||||
fizziness: 0.15
|
||||
|
||||
@@ -2111,9 +2111,9 @@
|
||||
- !type:AdjustReagent
|
||||
reagent: Theobromine
|
||||
amount: 0.05
|
||||
- !type:GenericStatusEffect
|
||||
key: Drowsiness
|
||||
time: 1.0
|
||||
- !type:ModifyStatusEffect
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 1
|
||||
type: Remove
|
||||
fizziness: 0.25
|
||||
|
||||
@@ -2142,9 +2142,9 @@
|
||||
- !type:AdjustReagent
|
||||
reagent: Theobromine
|
||||
amount: 0.05
|
||||
- !type:GenericStatusEffect
|
||||
key: Drowsiness
|
||||
time: 1.0
|
||||
- !type:ModifyStatusEffect
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 1
|
||||
type: Remove
|
||||
fizziness: 0.15
|
||||
|
||||
@@ -2173,9 +2173,9 @@
|
||||
- !type:AdjustReagent
|
||||
reagent: Theobromine
|
||||
amount: 0.05
|
||||
- !type:GenericStatusEffect
|
||||
key: Drowsiness
|
||||
time: 1.0
|
||||
- !type:ModifyStatusEffect
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 1
|
||||
type: Remove
|
||||
fizziness: 0.25
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
factor: 2
|
||||
- !type:GenericStatusEffect
|
||||
key: Drowsiness
|
||||
time: 2.0
|
||||
- !type:ModifyStatusEffect
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 2
|
||||
type: Remove
|
||||
- !type:AdjustReagent
|
||||
reagent: Theobromine
|
||||
@@ -105,9 +105,9 @@
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
factor: 2
|
||||
- !type:GenericStatusEffect
|
||||
key: Drowsiness
|
||||
time: 2.0
|
||||
- !type:ModifyStatusEffect
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 2
|
||||
type: Remove
|
||||
|
||||
- type: reagent
|
||||
@@ -161,9 +161,9 @@
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
factor: 2
|
||||
- !type:GenericStatusEffect
|
||||
key: Drowsiness
|
||||
time: 2.0
|
||||
- !type:ModifyStatusEffect
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 2
|
||||
type: Remove
|
||||
|
||||
- type: reagent
|
||||
@@ -342,9 +342,9 @@
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
factor: 6
|
||||
- !type:GenericStatusEffect
|
||||
key: Drowsiness
|
||||
time: 3.0
|
||||
- !type:ModifyStatusEffect
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 3
|
||||
type: Remove
|
||||
Poison:
|
||||
effects:
|
||||
@@ -383,9 +383,9 @@
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
factor: 2
|
||||
- !type:GenericStatusEffect
|
||||
key: Drowsiness
|
||||
time: 2.0
|
||||
- !type:ModifyStatusEffect
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 2
|
||||
type: Remove
|
||||
|
||||
- type: reagent
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
factor: 2
|
||||
- !type:GenericStatusEffect
|
||||
key: Drowsiness
|
||||
time: 1.0
|
||||
- !type:ModifyStatusEffect
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 1
|
||||
type: Remove
|
||||
|
||||
- type: reagent
|
||||
@@ -80,9 +80,9 @@
|
||||
effects:
|
||||
- !type:SatiateThirst
|
||||
factor: 2
|
||||
- !type:GenericStatusEffect
|
||||
key: Drowsiness
|
||||
time: 2.0
|
||||
- !type:ModifyStatusEffect
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 2
|
||||
type: Remove
|
||||
- !type:AdjustReagent
|
||||
reagent: Theobromine
|
||||
|
||||
@@ -360,7 +360,7 @@
|
||||
shouldHave: false
|
||||
walkSpeedModifier: 0.65
|
||||
sprintSpeedModifier: 0.65
|
||||
- !type:GenericStatusEffect
|
||||
- !type:ModifyStatusEffect
|
||||
conditions:
|
||||
- !type:ReagentThreshold
|
||||
reagent: NitrousOxide
|
||||
@@ -368,8 +368,7 @@
|
||||
- !type:OrganType
|
||||
type: Slime
|
||||
shouldHave: false
|
||||
key: ForcedSleep
|
||||
component: ForcedSleeping
|
||||
effectProto: StatusEffectForcedSleeping
|
||||
time: 3
|
||||
type: Add
|
||||
- !type:HealthChange
|
||||
|
||||
@@ -83,9 +83,8 @@
|
||||
key: Jitter
|
||||
time: 3.0
|
||||
type: Remove
|
||||
- !type:GenericStatusEffect
|
||||
key: Drowsiness
|
||||
component: Drowsiness
|
||||
- !type:ModifyStatusEffect
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 1.5
|
||||
type: Add
|
||||
refresh: false
|
||||
@@ -923,8 +922,8 @@
|
||||
- !type:GenericStatusEffect
|
||||
key: Stutter
|
||||
component: StutteringAccent
|
||||
- !type:GenericStatusEffect
|
||||
key: Drowsiness
|
||||
- !type:ModifyStatusEffect
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 10
|
||||
type: Remove
|
||||
- !type:ResetNarcolepsy
|
||||
@@ -948,8 +947,8 @@
|
||||
metabolisms:
|
||||
Medicine:
|
||||
effects:
|
||||
- !type:GenericStatusEffect
|
||||
key: Drowsiness
|
||||
- !type:ModifyStatusEffect
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 10
|
||||
type: Remove
|
||||
- !type:ResetNarcolepsy
|
||||
@@ -1390,9 +1389,8 @@
|
||||
emote: Yawn
|
||||
showInChat: true
|
||||
probability: 0.1
|
||||
- !type:GenericStatusEffect
|
||||
key: Drowsiness
|
||||
component: Drowsiness
|
||||
- !type:ModifyStatusEffect
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 4
|
||||
type: Add
|
||||
refresh: false
|
||||
|
||||
@@ -40,12 +40,12 @@
|
||||
key: KnockedDown
|
||||
time: 3
|
||||
type: Remove
|
||||
- !type:GenericStatusEffect
|
||||
- !type:ModifyStatusEffect
|
||||
conditions:
|
||||
- !type:ReagentThreshold
|
||||
reagent: Haloperidol
|
||||
max: 0.01
|
||||
key: Drowsiness
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 10
|
||||
type: Remove
|
||||
Medicine:
|
||||
@@ -88,12 +88,12 @@
|
||||
key: KnockedDown
|
||||
time: 1
|
||||
type: Remove
|
||||
- !type:GenericStatusEffect
|
||||
- !type:ModifyStatusEffect
|
||||
conditions:
|
||||
- !type:ReagentThreshold
|
||||
reagent: Haloperidol
|
||||
max: 0.01
|
||||
key: Drowsiness
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 10
|
||||
type: Remove
|
||||
- !type:PopupMessage
|
||||
@@ -152,16 +152,16 @@
|
||||
component: StaminaModifier
|
||||
time: 3
|
||||
type: Add
|
||||
- !type:GenericStatusEffect
|
||||
key: ForcedSleep
|
||||
- !type:ModifyStatusEffect
|
||||
effectProto: StatusEffectForcedSleeping
|
||||
time: 3
|
||||
type: Remove
|
||||
- !type:GenericStatusEffect
|
||||
- !type:ModifyStatusEffect
|
||||
conditions:
|
||||
- !type:ReagentThreshold
|
||||
reagent: Haloperidol
|
||||
max: 0.01
|
||||
key: Drowsiness
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 10
|
||||
type: Remove
|
||||
Medicine:
|
||||
@@ -296,14 +296,13 @@
|
||||
metabolisms:
|
||||
Narcotic:
|
||||
effects:
|
||||
- !type:GenericStatusEffect
|
||||
- !type:ModifyStatusEffect
|
||||
conditions:
|
||||
- !type:ReagentThreshold
|
||||
reagent: Nocturine
|
||||
min: 8
|
||||
key: ForcedSleep
|
||||
component: ForcedSleeping
|
||||
refresh: false
|
||||
effectProto: StatusEffectForcedSleeping
|
||||
time: 3
|
||||
type: Add
|
||||
|
||||
- type: reagent
|
||||
|
||||
@@ -63,9 +63,8 @@
|
||||
- !type:MovespeedModifier
|
||||
walkSpeedModifier: 0.65
|
||||
sprintSpeedModifier: 0.65
|
||||
- !type:GenericStatusEffect
|
||||
key: Drowsiness
|
||||
component: Drowsiness
|
||||
- !type:ModifyStatusEffect
|
||||
effectProto: StatusEffectDrowsiness
|
||||
time: 4
|
||||
type: Add
|
||||
refresh: false
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
# Status effect prototypes.
|
||||
# Holds no actual logic, just some basic data about the effect.
|
||||
|
||||
# Note: We have a new status effect system that needs all of these status effects to be fully ported to.
|
||||
# Adding new status effects under the old system is NOT RECOMMENDED.
|
||||
|
||||
- type: statusEffect
|
||||
id: Stun
|
||||
alert: Stun
|
||||
@@ -45,9 +48,6 @@
|
||||
id: Corporeal
|
||||
alert: Corporeal
|
||||
|
||||
- type: statusEffect
|
||||
id: ForcedSleep #I.e., they will not wake on damage or similar
|
||||
|
||||
- type: statusEffect
|
||||
id: TemporaryBlindness
|
||||
|
||||
@@ -66,9 +66,6 @@
|
||||
- type: statusEffect
|
||||
id: RadiationProtection
|
||||
|
||||
- type: statusEffect
|
||||
id: Drowsiness #blurs your vision and makes you randomly fall asleep
|
||||
|
||||
- type: statusEffect
|
||||
id: Adrenaline
|
||||
alert: Adrenaline
|
||||
|
||||
Reference in New Issue
Block a user