using Content.Shared._DV.Psionics.Components;
using Content.Shared._DV.Psionics.Components.PsionicPowers;
using Content.Shared._DV.Psionics.Events;
using Content.Shared._DV.Psionics.Events.PowerActionEvents;
using Content.Shared.Damage;
using Content.Shared.Damage.Systems;
using Content.Shared.Popups;
using Content.Shared.Revenant.Components;
using Content.Shared.StatusEffect;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
namespace Content.Shared._DV.Psionics.Systems.PsionicPowers;
///
/// This enables psionic users to dispel noospheric beings and actions.
///
public abstract class SharedDispelPowerSystem : BasePsionicPowerSystem
{
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
[Dependency] private readonly StatusEffectNew.StatusEffectsSystem _statusEffectsNew = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent(OnDispelled);
SubscribeLocalEvent(OnDmgDispelled);
SubscribeLocalEvent(OnPsionicShieldingStopped, null,[typeof(SharedPsionicSystem)]);
// Upstream stuff we're just gonna handle here
SubscribeLocalEvent(OnRevenantDispelled);
}
protected override void OnPowerInit(Entity power, ref MapInitEvent args)
{
base.OnPowerInit(power, ref args);
// Dispell psionics can now see invisible entities to dispell them.
Psionic.SetCanSeePsionicInvisiblity(power.Owner, true);
}
protected override void OnPowerUsed(Entity psionic, ref DispelPowerActionEvent args)
{
if (!Psionic.CanBeTargeted(args.Target, hasAggressor: args.Performer))
return;
var ev = new DispelledEvent(args.Performer, args.Target);
RaiseLocalEvent(args.Target, ev);
if (ev.Handled)
AfterPowerUsed(psionic, args.Performer);
}
protected override void OnPsionicallySuppressed(Entity power, ref PsionicSuppressedEvent args)
{
if (Timing.ApplyingState)
return;
// Don't let them see if they're suppressed.
Psionic.SetCanSeePsionicInvisiblity(args.Victim, false);
}
protected override void OnStoppedPsionicallySuppressed(Entity psionic, ref PsionicStoppedSuppressedEvent args)
{
if (Timing.ApplyingState)
return;
// Let mah people SEE
Psionic.SetCanSeePsionicInvisiblity(args.Victim, true);
}
///
/// This is necessary to avoid dispel users to lose their invisibility sight.
/// This fires after the System where losing psionic shielding makes you unable to see invisible entities.
///
/// The psionic who lost their shielding.
/// The event.
private void OnPsionicShieldingStopped(Entity psionic, ref PsionicStoppedShieldedEvent args)
{
if (_statusEffectsNew.HasStatusEffect(psionic, "StatusEffectPsionicsDisabled"))
return;
// Losing the shielding causes you to lose vision of the invisible. This is to prevent that.
Psionic.SetCanSeePsionicInvisiblity(args.Shielded, true);
}
protected override void OnMindBroken(Entity psionic, ref PsionicMindBrokenEvent args)
{
base.OnMindBroken(psionic, ref args);
// If the mindbreak was successful, make 'em blind.
if (!psionic.Comp.Deleted)
return;
Psionic.SetCanSeePsionicInvisiblity(psionic, false);
}
private void OnDispelled(Entity dispellable, ref DispelledEvent args)
{
QueueDel(dispellable);
Spawn("Ash", Transform(dispellable).Coordinates);
Popup.PopupPredicted(Loc.GetString("psionic-burns-up", ("item", dispellable)), dispellable, args.Dispeller, PopupType.MediumCaution);
_audio.PlayPredicted(dispellable.Comp.DispelSound, dispellable.Owner, args.Dispeller);
args.Handled = true;
}
private void OnDmgDispelled(Entity damaged, ref DispelledEvent args)
{
var damage = damaged.Comp.Damage;
var modifier = Random.NextFloat(damaged.Comp.Variance, 1 + damaged.Comp.Variance);
damage *= modifier;
DealDispelDamage(damaged, damage, args.Dispeller, damaged.Comp.DispelSound);
args.Handled = true;
}
private void OnRevenantDispelled(Entity revenant, ref DispelledEvent args)
{
DealDispelDamage(revenant, dispeller: args.Dispeller);
// TODO: Port over the new StatusEffectSystem when upstream ports over the Corporeal status effect to the new system.
_statusEffects.TryAddStatusEffect(revenant, "Corporeal", TimeSpan.FromSeconds(30), false, "Corporeal");
args.Handled = true;
}
public void DealDispelDamage(EntityUid dispelled, DamageSpecifier? damage = null, EntityUid? dispeller = null, SoundSpecifier? sound = null)
{
if (Deleted(dispelled))
return;
Popup.PopupPredicted(Loc.GetString("psionic-burn-resist", ("item", dispelled)), dispelled, dispeller, PopupType.SmallCaution);
_audio.PlayPredicted(sound, dispelled, dispeller);
if (damage == null)
{
damage = new DamageSpecifier();
damage.DamageDict.Add("Blunt", 100);
}
_damageable.TryChangeDamage(dispelled, damage, ignoreResistances: true);
}
}