using System.Diagnostics.CodeAnalysis; using Robust.Shared.Timing; namespace Content.Shared.Timing; public sealed class UseDelaySystem : EntitySystem { [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly MetaDataSystem _metadata = default!; private const string DefaultId = "default"; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnUnpaused); } private void OnMapInit(Entity ent, ref MapInitEvent args) { // Set default delay length from the prototype // This makes it easier for simple use cases that only need a single delay SetLength(ent, ent.Comp.Delay, DefaultId); } private void OnUnpaused(Entity ent, ref EntityUnpausedEvent args) { // We have to do this manually, since it's not just a single field. foreach (var entry in ent.Comp.Delays.Values) { entry.EndTime += args.PausedTime; } } /// /// Sets the length of the delay with the specified ID. /// public bool SetLength(Entity ent, TimeSpan length, string id = DefaultId) { if (ent.Comp.Delays.TryGetValue(id, out var entry)) { if (entry.Length == length) return true; entry.Length = length; } else { ent.Comp.Delays.Add(id, new UseDelayInfo(length)); } Dirty(ent); return true; } /// /// Returns true if the entity has a currently active UseDelay with the specified ID. /// public bool IsDelayed(Entity ent, string id = DefaultId) { if (!ent.Comp.Delays.TryGetValue(id, out var entry)) return false; return entry.EndTime >= _gameTiming.CurTime; } /// /// Cancels the delay with the specified ID. /// public void CancelDelay(Entity ent, string id = DefaultId) { if (!ent.Comp.Delays.TryGetValue(id, out var entry)) return; entry.EndTime = _gameTiming.CurTime; Dirty(ent); } /// /// Tries to get info about the delay with the specified ID. See . /// /// /// /// /// public bool TryGetDelayInfo(Entity ent, [NotNullWhen(true)] out UseDelayInfo? info, string id = DefaultId) { return ent.Comp.Delays.TryGetValue(id, out info); } /// /// Returns info for the delay that will end farthest in the future. /// public UseDelayInfo GetLastEndingDelay(Entity ent) { var last = ent.Comp.Delays[DefaultId]; foreach (var entry in ent.Comp.Delays) { if (entry.Value.EndTime > last.EndTime) last = entry.Value; } return last; } /// /// Resets the delay with the specified ID for this entity if possible. /// /// Check if the entity has an ongoing delay with the specified ID. /// If it does, return false and don't reset it. /// Otherwise reset it and return true. public bool TryResetDelay(Entity ent, bool checkDelayed = false, string id = DefaultId) { if (checkDelayed && IsDelayed(ent, id)) return false; if (!ent.Comp.Delays.TryGetValue(id, out var entry)) return false; var curTime = _gameTiming.CurTime; entry.StartTime = curTime; entry.EndTime = curTime - _metadata.GetPauseTime(ent) + entry.Length; Dirty(ent); return true; } public bool TryResetDelay(EntityUid uid, bool checkDelayed = false, UseDelayComponent? component = null, string id = DefaultId) { if (!Resolve(uid, ref component, false)) return false; return TryResetDelay((uid, component), checkDelayed, id); } /// /// Resets all delays on the entity. /// public void ResetAllDelays(Entity ent) { var curTime = _gameTiming.CurTime; foreach (var entry in ent.Comp.Delays.Values) { entry.StartTime = curTime; entry.EndTime = curTime - _metadata.GetPauseTime(ent) + entry.Length; } Dirty(ent); } }