Add a sleep delay to Nocturine (NewStatusEffect version) (#40231)

* Initial commit

* Minor fix

* Why is this uncommented here? Hmmm

* No wait this can't be here, oops

* Do better time

* Also guidebook

* Review changes

* Add rejuvination, fix mispredicts
This commit is contained in:
SlamBamActionman
2025-09-26 22:05:34 +02:00
committed by GitHub
parent dc3f5e3564
commit c7117f38ac
7 changed files with 179 additions and 33 deletions

View File

@@ -46,6 +46,8 @@ public sealed partial class StatusEffectsSystem : EntitySystem
var query = EntityQueryEnumerator<StatusEffectComponent>();
while (query.MoveNext(out var ent, out var effect))
{
TryApplyStatusEffect((ent, effect));
if (effect.EndEffectTime is null)
continue;
@@ -88,9 +90,6 @@ public sealed partial class StatusEffectsSystem : EntitySystem
statusComp.AppliedTo = ent;
Dirty(args.Entity, statusComp);
}
var ev = new StatusEffectAppliedEvent(ent);
RaiseLocalEvent(args.Entity, ref ev);
}
private void OnEntityRemoved(Entity<StatusEffectContainerComponent> ent, ref EntRemovedFromContainerMessage args)
@@ -121,6 +120,29 @@ public sealed partial class StatusEffectsSystem : EntitySystem
PredictedQueueDel(ent.Owner);
}
/// <summary>
/// Applies the status effect, i.e. starts it after it has been added. Ensures delayed start times trigger when they should.
/// </summary>
/// <param name="statusEffectEnt">The status effect entity.</param>
/// <returns>Returns true if the effect is applied.</returns>
private bool TryApplyStatusEffect(Entity<StatusEffectComponent> statusEffectEnt)
{
if (!statusEffectEnt.Comp.Applied &&
statusEffectEnt.Comp.AppliedTo != null &&
_timing.CurTime >= statusEffectEnt.Comp.StartEffectTime)
{
var ev = new StatusEffectAppliedEvent(statusEffectEnt.Comp.AppliedTo.Value);
RaiseLocalEvent(statusEffectEnt, ref ev);
statusEffectEnt.Comp.Applied = true;
DirtyField(statusEffectEnt, statusEffectEnt.Comp, nameof(StatusEffectComponent.StartEffectTime));
return true;
}
return false;
}
public bool CanAddStatusEffect(EntityUid uid, EntProtoId effectProto)
{
if (!_proto.Resolve(effectProto, out var effectProtoData))
@@ -148,12 +170,14 @@ public sealed partial class StatusEffectsSystem : EntitySystem
/// <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="delay">The delay of the effect. Leave null and the effect will be immediate.</param>
/// <param name="statusEffect">The EntityUid of the status effect we have just created or null if we couldn't create one.</param>
private bool TryAddStatusEffect(
EntityUid target,
EntProtoId effectProto,
[NotNullWhen(true)] out EntityUid? statusEffect,
TimeSpan? duration = null
TimeSpan? duration = null,
TimeSpan? delay = null
)
{
statusEffect = null;
@@ -177,7 +201,13 @@ public sealed partial class StatusEffectsSystem : EntitySystem
return false;
statusEffect = effect;
SetStatusEffectEndTime((effect.Value, effectComp), _timing.CurTime + duration);
var endTime = delay == null ? _timing.CurTime + duration : _timing.CurTime + delay + duration;
SetStatusEffectEndTime((effect.Value, effectComp), endTime);
var startTime = delay == null ? TimeSpan.Zero : _timing.CurTime + delay.Value;
SetStatusEffectStartTime(effect.Value, startTime);
TryApplyStatusEffect((effect.Value, effectComp));
return true;
}
@@ -204,6 +234,28 @@ public sealed partial class StatusEffectsSystem : EntitySystem
SetStatusEffectEndTime(effect, newEndTime);
}
private void UpdateStatusEffectDelay(Entity<StatusEffectComponent?> effect, TimeSpan? delay)
{
if (!_effectQuery.Resolve(effect, ref effect.Comp))
return;
// It's already started!
if (_timing.CurTime >= effect.Comp.StartEffectTime)
return;
var newStartTime = TimeSpan.Zero;
if (delay is not null)
{
// Don't update time to a smaller timespan...
newStartTime = _timing.CurTime + delay.Value;
if (effect.Comp.StartEffectTime < newStartTime)
return;
}
SetStatusEffectStartTime(effect, newStartTime);
}
private void AddStatusEffectTime(Entity<StatusEffectComponent?> effect, TimeSpan delta)
{
if (!_effectQuery.Resolve(effect, ref effect.Comp))
@@ -233,7 +285,26 @@ public sealed partial class StatusEffectsSystem : EntitySystem
var ev = new StatusEffectEndTimeUpdatedEvent(appliedTo, endTime);
RaiseLocalEvent(ent, ref ev);
Dirty(ent);
DirtyField(ent, ent.Comp, nameof(StatusEffectComponent.EndEffectTime));
}
private void SetStatusEffectStartTime(Entity<StatusEffectComponent?> ent, TimeSpan startTime)
{
if (!_effectQuery.Resolve(ent, ref ent.Comp))
return;
if (ent.Comp.StartEffectTime == startTime)
return;
ent.Comp.StartEffectTime = startTime;
if (ent.Comp.AppliedTo is not { } appliedTo)
return; // Not much we can do!
var ev = new StatusEffectStartTimeUpdatedEvent(appliedTo, startTime);
RaiseLocalEvent(ent, ref ev);
DirtyField(ent, ent.Comp, nameof(StatusEffectComponent.StartEffectTime));
}
}
@@ -262,3 +333,11 @@ public record struct BeforeStatusEffectAddedEvent(EntProtoId Effect, bool Cancel
/// <param name="EndTime">The new end time of the status effect, included for convenience.</param>
[ByRefEvent]
public record struct StatusEffectEndTimeUpdatedEvent(EntityUid Target, TimeSpan? EndTime);
/// <summary>
/// Raised on an effect entity when its <see cref="StatusEffectComponent.StartEffectTime"/> is updated in any way.
/// </summary>
/// <param name="Target">The entity the effect is attached to.</param>
/// <param name="StartTime">The new start time of the status effect, included for convenience.</param>
[ByRefEvent]
public record struct StatusEffectStartTimeUpdatedEvent(EntityUid Target, TimeSpan? StartTime);