/// <summary> /// Slows down the mob's walking/running speed temporarily /// </summary> public bool TrySlowdown(EntityUid uid, TimeSpan time, bool refresh, float walkSpeedMultiplier = 1f, float runSpeedMultiplier = 1f, StatusEffectsComponent?status = null, SharedAlertsComponent?alerts = null) { if (!Resolve(uid, ref status)) { return(false); } // "Optional" component. Resolve(uid, ref alerts, false); if (time <= TimeSpan.Zero) { return(false); } if (_statusEffectSystem.TryAddStatusEffect <SlowedDownComponent>(uid, "SlowedDown", time, refresh, status, alerts)) { var slowed = EntityManager.GetComponent <SlowedDownComponent>(uid); // Doesn't make much sense to have the "TrySlowdown" method speed up entities now does it? walkSpeedMultiplier = Math.Clamp(walkSpeedMultiplier, 0f, 1f); runSpeedMultiplier = Math.Clamp(runSpeedMultiplier, 0f, 1f); slowed.WalkSpeedModifier *= walkSpeedMultiplier; slowed.SprintSpeedModifier *= runSpeedMultiplier; _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(uid); return(true); } return(false); }
/// <summary> /// Applies a jitter effect to the specified entity. /// You can apply this to any entity whatsoever, so be careful what you use it on! /// </summary> /// <remarks> /// If the entity is already jittering, the jitter values will be updated but only if they're greater /// than the current ones and <see cref="forceValueChange"/> is false. /// </remarks> /// <param name="uid">Entity in question.</param> /// <param name="time">For how much time to apply the effect.</param> /// <param name="refresh">The status effect cooldown should be refreshed (true) or accumulated (false).</param> /// <param name="amplitude">Jitteriness of the animation. See <see cref="MaxAmplitude"/> and <see cref="MinAmplitude"/>.</param> /// <param name="frequency">Frequency for jittering. See <see cref="MaxFrequency"/> and <see cref="MinFrequency"/>.</param> /// <param name="forceValueChange">Whether to change any existing jitter value even if they're greater than the ones we're setting.</param> /// <param name="status">The status effects component to modify.</param> /// <param name="alerts">The alerts component.</param> public void DoJitter(EntityUid uid, TimeSpan time, bool refresh, float amplitude = 10f, float frequency = 4f, bool forceValueChange = false, StatusEffectsComponent?status = null, SharedAlertsComponent?alerts = null) { if (!Resolve(uid, ref status, false)) { return; } amplitude = Math.Clamp(amplitude, MinAmplitude, MaxAmplitude); frequency = Math.Clamp(frequency, MinFrequency, MaxFrequency); if (StatusEffects.TryAddStatusEffect <JitteringComponent>(uid, "Jitter", time, refresh, status, alerts)) { var jittering = EntityManager.GetComponent <JitteringComponent>(uid); if (forceValueChange || jittering.Amplitude < amplitude) { jittering.Amplitude = amplitude; } if (forceValueChange || jittering.Frequency < frequency) { jittering.Frequency = frequency; } } }
/// <summary> /// Tries to add a status effect to an entity, with a given component added as well. /// </summary> /// <param name="uid">The entity to add the effect to.</param> /// <param name="key">The status effect ID to add.</param> /// <param name="time">How long the effect should last for.</param> /// <param name="refresh">The status effect cooldown should be refreshed (true) or accumulated (false).</param> /// <param name="status">The status effects component to change, if you already have it.</param> /// <param name="alerts">The alerts component to modify, if the status effect has an alert.</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> public bool TryAddStatusEffect <T>(EntityUid uid, string key, TimeSpan time, bool refresh, StatusEffectsComponent?status = null, SharedAlertsComponent?alerts = null) where T : Component, new() { if (!Resolve(uid, ref status, false)) { return(false); } Resolve(uid, ref alerts, false); if (TryAddStatusEffect(uid, key, time, refresh, status, alerts)) { // If they already have the comp, we just won't bother updating anything. if (!EntityManager.HasComponent <T>(uid)) { var comp = EntityManager.AddComponent <T>(uid); status.ActiveEffects[key].RelevantComponent = comp.Name; } return(true); } return(false); }
public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool refresh, string component, StatusEffectsComponent?status = null, SharedAlertsComponent?alerts = null) { if (!Resolve(uid, ref status, false)) { return(false); } Resolve(uid, ref alerts, false); if (TryAddStatusEffect(uid, key, time, refresh, status, alerts)) { // If they already have the comp, we just won't bother updating anything. if (!EntityManager.HasComponent(uid, _componentFactory.GetRegistration(component).Type)) { // F**k this shit I hate it var newComponent = (Component)_componentFactory.GetComponent(component); newComponent.Owner = uid; EntityManager.AddComponent(uid, newComponent); status.ActiveEffects[key].RelevantComponent = component; } return(true); } return(false); }
/// <summary> /// Tries to add to the timer of an already existing status effect. /// </summary> /// <param name="uid">The entity to add time to.</param> /// <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> public bool TryAddTime(EntityUid uid, string key, TimeSpan time, StatusEffectsComponent?status = null, SharedAlertsComponent?alert = null) { if (!Resolve(uid, ref status, false)) { return(false); } Resolve(uid, ref alert, false); if (!HasStatusEffect(uid, key, status)) { return(false); } var timer = status.ActiveEffects[key].Cooldown; timer.Item2 += time; status.ActiveEffects[key].Cooldown = timer; if (_prototypeManager.TryIndex <StatusEffectPrototype>(key, out var proto) && alert != null && proto.Alert != null) { alert.ShowAlert(proto.Alert.Value, cooldown: GetAlertCooldown(uid, proto.Alert.Value, status)); } return(true); }
/// <summary> /// Applies knockdown and stun to the entity temporarily. /// </summary> public bool TryParalyze(EntityUid uid, TimeSpan time, StatusEffectsComponent?status = null, SharedAlertsComponent?alerts = null) { // Optional component. Resolve(uid, ref alerts, false); return(TryKnockdown(uid, time, status, alerts) && TryStun(uid, time, status, alerts)); }
/// <summary> /// Tries to add a status effect to an entity with a certain timer. /// </summary> /// <param name="uid">The entity to add the effect to.</param> /// <param name="key">The status effect ID to add.</param> /// <param name="time">How long the effect should last for.</param> /// <param name="refresh">The status effect cooldown should be refreshed (true) or accumulated (false).</param> /// <param name="status">The status effects component to change, if you already have it.</param> /// <param name="alerts">The alerts component to modify, if the status effect has an alert.</param> /// <returns>False if the effect could not be added, or if the effect already existed.</returns> /// <remarks> /// This obviously does not add any actual 'effects' on its own. Use the generic overload, /// which takes in a component type, if you want to automatically add and remove a component. /// /// 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> public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool refresh, StatusEffectsComponent?status = null, SharedAlertsComponent?alerts = null) { if (!Resolve(uid, ref status, false)) { return(false); } if (!CanApplyEffect(uid, key, status)) { return(false); } Resolve(uid, ref alerts, false); // we already checked if it has the index in CanApplyEffect so a straight index and not tryindex here // is fine var proto = _prototypeManager.Index <StatusEffectPrototype>(key); (TimeSpan, TimeSpan)cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + time); if (HasStatusEffect(uid, key, status)) { status.ActiveEffects[key].CooldownRefresh = refresh; if (refresh) { //Making sure we don't reset a longer cooldown by applying a shorter one. if ((status.ActiveEffects[key].Cooldown.Item2 - _gameTiming.CurTime) < time) { //Refresh cooldown time. status.ActiveEffects[key].Cooldown = cooldown; } } else { //Accumulate cooldown time. status.ActiveEffects[key].Cooldown.Item2 += time; } } else { status.ActiveEffects.Add(key, new StatusEffectState(cooldown, refresh, null)); } if (proto.Alert != null && alerts != null) { alerts.ShowAlert(proto.Alert.Value, cooldown: GetAlertCooldown(uid, proto.Alert.Value, status)); } status.Dirty(); // event? return(true); }
/// <summary> /// Knocks down the entity, making it fall to the ground. /// </summary> public bool TryKnockdown(EntityUid uid, TimeSpan time, StatusEffectsComponent?status = null, SharedAlertsComponent?alerts = null) { if (time <= TimeSpan.Zero) { return(false); } Resolve(uid, ref alerts, false); return(_statusEffectSystem.TryAddStatusEffect <KnockedDownComponent>(uid, "KnockedDown", time, alerts: alerts)); }
/// <summary> /// Attempts to remove a status effect from an entity. /// </summary> /// <param name="uid">The entity to remove an effect from.</param> /// <param name="key">The effect ID to remove.</param> /// <param name="status">The status effects component to change, if you already have it.</param> /// <param name="alerts">The alerts component to modify, if the status effect has an alert.</param> /// <returns>False if the effect could not be removed, true otherwise.</returns> /// <remarks> /// 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> public bool TryRemoveStatusEffect(EntityUid uid, string key, StatusEffectsComponent?status = null, SharedAlertsComponent?alerts = null) { if (!Resolve(uid, ref status, false)) { return(false); } if (!status.ActiveEffects.ContainsKey(key)) { return(false); } if (!_prototypeManager.TryIndex <StatusEffectPrototype>(key, out var proto)) { return(false); } Resolve(uid, ref alerts, false); var state = status.ActiveEffects[key]; // There are cases where a status effect component might be server-only, so TryGetRegistration... if (state.RelevantComponent != null && _componentFactory.TryGetRegistration(state.RelevantComponent, out var registration)) { var type = registration.Type; // Make sure the component is actually there first. // Maybe a badmin badminned the component away, // or perhaps, on the client, the component deletion sync // was faster than prediction could predict. Either way, let's not assume the component exists. if (EntityManager.HasComponent(uid, type)) { EntityManager.RemoveComponent(uid, type); } } if (proto.Alert != null && alerts != null) { alerts.ClearAlert(proto.Alert.Value); } status.ActiveEffects.Remove(key); status.Dirty(); // event? return(true); }
// TODO STUN: Make events for different things. (Getting modifiers, attempt events, informative events...) /// <summary> /// Stuns the entity, disallowing it from doing many interactions temporarily. /// </summary> public bool TryStun(EntityUid uid, TimeSpan time, bool refresh, StatusEffectsComponent?status = null, SharedAlertsComponent?alerts = null) { if (time <= TimeSpan.Zero) { return(false); } if (!Resolve(uid, ref status, false)) { return(false); } Resolve(uid, ref alerts, false); return(_statusEffectSystem.TryAddStatusEffect <StunnedComponent>(uid, "Stun", time, refresh, alerts: alerts)); }
/// <summary> /// Tries to add a status effect to an entity with a certain timer. /// </summary> /// <param name="uid">The entity to add the effect to.</param> /// <param name="key">The status effect ID to add.</param> /// <param name="time">How long the effect should last for.</param> /// <param name="status">The status effects component to change, if you already have it.</param> /// <param name="alerts">The alerts component to modify, if the status effect has an alert.</param> /// <returns>False if the effect could not be added, or if the effect already existed.</returns> /// <remarks> /// This obviously does not add any actual 'effects' on its own. Use the generic overload, /// which takes in a component type, if you want to automatically add and remove a component. /// /// 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> public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, StatusEffectsComponent?status = null, SharedAlertsComponent?alerts = null) { if (!Resolve(uid, ref status, false)) { return(false); } if (!CanApplyEffect(uid, key, status)) { return(false); } Resolve(uid, ref alerts, false); // we already checked if it has the index in CanApplyEffect so a straight index and not tryindex here // is fine var proto = _prototypeManager.Index <StatusEffectPrototype>(key); (TimeSpan, TimeSpan)cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + time); // If they already have this status effect, just bulldoze its cooldown in favor of the new one // and keep the relevant component the same. if (HasStatusEffect(uid, key, status)) { status.ActiveEffects[key] = new StatusEffectState(cooldown, status.ActiveEffects[key].RelevantComponent); } else { status.ActiveEffects.Add(key, new StatusEffectState(cooldown, null)); } if (proto.Alert != null && alerts != null) { alerts.ShowAlert(proto.Alert.Value, cooldown: GetAlertCooldown(uid, proto.Alert.Value, status)); } status.Dirty(); // event? return(true); }
/// <summary> /// Tries to remove all status effects from a given entity. /// </summary> /// <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> /// <param name="alerts">The alerts component to modify, if the status effect has an alert.</param> /// <returns>False if any status effects failed to be removed, true if they all did.</returns> public bool TryRemoveAllStatusEffects(EntityUid uid, StatusEffectsComponent?status = null, SharedAlertsComponent?alerts = null) { if (!Resolve(uid, ref status, false)) { return(false); } Resolve(uid, ref alerts, false); bool failed = false; foreach (var effect in status.ActiveEffects) { if (!TryRemoveStatusEffect(uid, effect.Key, status, alerts)) { failed = true; } } return(failed); }
// For code in shared... I imagine we ain't getting accent prediction anytime soon so let's not bother. public virtual void DoStutter(EntityUid uid, TimeSpan time, bool refresh, StatusEffectsComponent?status = null, SharedAlertsComponent?alerts = null) { }