using System.Diagnostics.CodeAnalysis; using Content.Shared.StatusEffectNew.Components; using Robust.Shared.Prototypes; namespace Content.Shared.StatusEffectNew; public abstract partial class SharedStatusEffectsSystem { /// /// 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. /// /// The target entity to which the effect should be added. /// ProtoId of the status effect entity. Make sure it has StatusEffectComponent on it. /// Duration of status effect. Leave null and the effect will be permanent until it is removed using TryRemoveStatusEffect. /// /// 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. /// 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(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; } /// /// 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. /// 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; } /// /// Checks whether the specified entity is under a specific status effect. /// 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; } /// /// Attempting to retrieve the EntityUid of a status effect from an entity. /// 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; } /// /// Attempting to retrieve the time of a status effect from an entity. /// /// The target entity on which the effect is applied. /// The prototype ID of the status effect to retrieve. /// The output tuple containing the effect entity and its remaining time. /// Optional. The status effect container component of the entity. 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; } /// /// Attempts to edit the remaining time for a status effect on an entity. /// /// The target entity on which the effect is applied. /// The prototype ID of the status effect to modify. /// /// The time adjustment to apply to the status effect. Positive values extend the duration, /// while negative values reduce it. /// /// True if duration was edited successfully, false otherwise. 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; } /// /// Attempts to set the remaining time for a status effect on an entity. /// /// The target entity on which the effect is applied. /// The prototype ID of the status effect to modify. /// The new duration for the status effect. /// True if duration was set successfully, false otherwise. 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; } /// /// Checks if the specified component is present on any of the entity's status effects. /// public bool HasEffectComp(EntityUid? target) where T : IComponent { if (!_containerQuery.TryComp(target, out var container)) return false; foreach (var effect in container.ActiveStatusEffects) { if (HasComp(effect)) return true; } return false; } /// /// Returns all status effects that have the specified component. /// public bool TryEffectsWithComp(EntityUid? target, [NotNullWhen(true)] out HashSet>? effects) where T : IComponent { effects = null; if (!_containerQuery.TryComp(target, out var container)) return false; foreach (var effect in container.ActiveStatusEffects) { if (!TryComp(effect, out var statusComp)) continue; if (TryComp(effect, out var comp)) { effects ??= []; effects.Add((effect, comp, statusComp)); } } return effects != null; } }