From 99ee3122f244ebede2d8e3960475f79240ca07c3 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 23 Sep 2024 20:56:34 -0400 Subject: [PATCH] Fix HealingWord & Revivify Bugs (#949) # Description Playtesting uncovered a few bugs with the HealOtherSystem, these are luckily pretty simple to fix. I also made a few of the functions in this system nullable as a performance optimization. # Changelog :cl: - fix: Fixed a bug where Breath of Life and Healing Word would set living people to crit, which would knock them down. - fix: Fixed a bug where Breath of Life could revive people who were rotten(It will still heal them and reduce the rot timer as intended, but will not revive unless said rot timer reduction brings them below the 10 minute threshold). - add: The Do-After bar for Breath of Life and Healing Word is now hidden if glimmer is low enough. The threshold for which scales with your Dampening stat. More Dampening = stealthier casting. --- .../Abilities/HealOtherPowerSystem.cs | 32 +++++++++++++------ .../PsionicHealOtherPowerActionEvent.cs | 11 ++++--- Content.Shared/Psionics/Events.cs | 4 +-- Resources/Prototypes/Actions/psionics.yml | 10 +++--- 4 files changed, 37 insertions(+), 20 deletions(-) diff --git a/Content.Server/Abilities/Psionics/Abilities/HealOtherPowerSystem.cs b/Content.Server/Abilities/Psionics/Abilities/HealOtherPowerSystem.cs index 85bae78dc6..35b5e6a238 100644 --- a/Content.Server/Abilities/Psionics/Abilities/HealOtherPowerSystem.cs +++ b/Content.Server/Abilities/Psionics/Abilities/HealOtherPowerSystem.cs @@ -53,14 +53,14 @@ private void OnPowerUsed(EntityUid uid, PsionicComponent component, PsionicHealO else ActivatePower(uid, component, args); if (args.PopupText is not null - && _glimmer.Glimmer > args.GlimmerObviousPopupThreshold * component.CurrentDampening) + && _glimmer.Glimmer > args.GlimmerPopupThreshold * component.CurrentDampening) _popupSystem.PopupEntity(Loc.GetString(args.PopupText, ("entity", uid)), uid, Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !_examine.InRangeUnOccluded(uid, entity, ExamineRange, null)), true, args.PopupType); if (args.PlaySound - && _glimmer.Glimmer > args.GlimmerObviousSoundThreshold * component.CurrentDampening) + && _glimmer.Glimmer > args.GlimmerSoundThreshold * component.CurrentDampening) _audioSystem.PlayPvs(args.SoundUse, uid, args.AudioParams); // Sanitize the Glimmer inputs because otherwise the game will crash if someone makes MaxGlimmer lower than MinGlimmer. @@ -76,13 +76,16 @@ private void OnPowerUsed(EntityUid uid, PsionicComponent component, PsionicHealO private void AttemptDoAfter(EntityUid uid, PsionicComponent component, PsionicHealOtherPowerActionEvent args) { var ev = new PsionicHealOtherDoAfterEvent(_gameTiming.CurTime); - ev.HealingAmount = args.HealingAmount; - ev.RotReduction = args.RotReduction; + if (args.HealingAmount is not null) + ev.HealingAmount = args.HealingAmount; + if (args.RotReduction is not null) + ev.RotReduction = args.RotReduction.Value; ev.DoRevive = args.DoRevive; var doAfterArgs = new DoAfterArgs(EntityManager, uid, args.UseDelay, ev, uid, target: args.Target) { BreakOnUserMove = args.BreakOnUserMove, BreakOnTargetMove = args.BreakOnTargetMove, + Hidden = _glimmer.Glimmer > args.GlimmerDoAfterVisibilityThreshold * component.CurrentDampening, }; if (!_doAfterSystem.TryStartDoAfter(doAfterArgs, out var doAfterId)) @@ -104,7 +107,8 @@ private void OnDispelled(EntityUid uid, PsionicComponent component, DispelledEve private void OnDoAfter(EntityUid uid, PsionicComponent component, PsionicHealOtherDoAfterEvent args) { // It's entirely possible for the caster to stop being Psionic(due to mindbreaking) mid cast - if (component is null) + if (component is null + || args.Cancelled) return; component.DoAfter = null; @@ -112,15 +116,19 @@ private void OnDoAfter(EntityUid uid, PsionicComponent component, PsionicHealOth if (args.Target is null) return; - _rotting.ReduceAccumulator(args.Target.Value, TimeSpan.FromSeconds(args.RotReduction * component.CurrentAmplification)); + if (args.RotReduction is not null) + _rotting.ReduceAccumulator(args.Target.Value, TimeSpan.FromSeconds(args.RotReduction.Value * component.CurrentAmplification)); if (!TryComp(args.Target.Value, out var damageableComponent)) return; - _damageable.TryChangeDamage(args.Target.Value, args.HealingAmount * component.CurrentAmplification, true, false, damageableComponent, uid); + if (args.HealingAmount is not null) + _damageable.TryChangeDamage(args.Target.Value, args.HealingAmount * component.CurrentAmplification, true, false, damageableComponent, uid); if (!args.DoRevive - || !TryComp(args.Target, out var mob) + || _rotting.IsRotten(args.Target.Value) + || !TryComp(args.Target.Value, out var mob) + || !_mobState.IsDead(args.Target.Value, mob) || !_mobThreshold.TryGetThresholdForState(args.Target.Value, MobState.Dead, out var threshold) || damageableComponent.TotalDamage > threshold) return; @@ -134,15 +142,19 @@ private void ActivatePower(EntityUid uid, PsionicComponent component, PsionicHea if (component is null) return; - _rotting.ReduceAccumulator(args.Target, TimeSpan.FromSeconds(args.RotReduction * component.CurrentAmplification)); + if (args.RotReduction is not null) + _rotting.ReduceAccumulator(args.Target, TimeSpan.FromSeconds(args.RotReduction.Value * component.CurrentAmplification)); if (!TryComp(args.Target, out var damageableComponent)) return; - _damageable.TryChangeDamage(args.Target, args.HealingAmount * component.CurrentAmplification, true, false, damageableComponent, uid); + if (args.HealingAmount is not null) + _damageable.TryChangeDamage(args.Target, args.HealingAmount * component.CurrentAmplification, true, false, damageableComponent, uid); if (!args.DoRevive + || _rotting.IsRotten(args.Target) || !TryComp(args.Target, out var mob) + || !_mobState.IsDead(args.Target, mob) || !_mobThreshold.TryGetThresholdForState(args.Target, MobState.Dead, out var threshold) || damageableComponent.TotalDamage > threshold) return; diff --git a/Content.Shared/Actions/Events/PsionicHealOtherPowerActionEvent.cs b/Content.Shared/Actions/Events/PsionicHealOtherPowerActionEvent.cs index 8cf11b9e66..0001c7842d 100644 --- a/Content.Shared/Actions/Events/PsionicHealOtherPowerActionEvent.cs +++ b/Content.Shared/Actions/Events/PsionicHealOtherPowerActionEvent.cs @@ -6,7 +6,7 @@ namespace Content.Shared.Actions.Events; public sealed partial class PsionicHealOtherPowerActionEvent : EntityTargetActionEvent { [DataField] - public DamageSpecifier HealingAmount = default!; + public DamageSpecifier? HealingAmount = default!; [DataField] public string PowerName; @@ -19,7 +19,7 @@ public sealed partial class PsionicHealOtherPowerActionEvent : EntityTargetActio public string? PopupText; [DataField] - public float RotReduction; + public float? RotReduction; [DataField] public bool DoRevive; @@ -40,10 +40,13 @@ public sealed partial class PsionicHealOtherPowerActionEvent : EntityTargetActio public int MaxGlimmer = 12; [DataField] - public int GlimmerObviousSoundThreshold; + public int GlimmerSoundThreshold; [DataField] - public int GlimmerObviousPopupThreshold; + public int GlimmerPopupThreshold; + + [DataField] + public int GlimmerDoAfterVisibilityThreshold; [DataField] public PopupType PopupType = PopupType.Medium; diff --git a/Content.Shared/Psionics/Events.cs b/Content.Shared/Psionics/Events.cs index f110c9c405..744dd3b6ea 100644 --- a/Content.Shared/Psionics/Events.cs +++ b/Content.Shared/Psionics/Events.cs @@ -42,10 +42,10 @@ public sealed partial class PsionicHealOtherDoAfterEvent : DoAfterEvent public TimeSpan StartedAt; [DataField] - public DamageSpecifier HealingAmount = default!; + public DamageSpecifier? HealingAmount = default!; [DataField] - public float RotReduction; + public float? RotReduction; [DataField] public bool DoRevive; diff --git a/Resources/Prototypes/Actions/psionics.yml b/Resources/Prototypes/Actions/psionics.yml index d38608a469..82e356a11f 100644 --- a/Resources/Prototypes/Actions/psionics.yml +++ b/Resources/Prototypes/Actions/psionics.yml @@ -179,8 +179,9 @@ playSound: true minGlimmer: 2 maxGlimmer: 4 - glimmerObviousSoundThreshold: 100 - glimmerObviousPopupThreshold: 200 + glimmerSoundThreshold: 100 + glimmerPopupThreshold: 200 + glimmerDoAfterVisibilityThreshold: 70 - type: entity id: ActionRevivify @@ -217,5 +218,6 @@ playSound: true minGlimmer: 10 # These also get multiplied by caster stats. So, maxGlimmer: 15 # keeping in mind the ~3.5x multiplier, this spikes glimmer by as much as 60 points. - glimmerObviousSoundThreshold: 50 - glimmerObviousPopupThreshold: 100 + glimmerSoundThreshold: 50 + glimmerPopupThreshold: 100 + glimmerDoAfterVisibilityThreshold: 35