Delta-v/Content.Server/_DV/Psionics/Systems/PsionicPowers/TelegnosisPowerSystem.cs

72 lines
3.2 KiB
C#

using System.Numerics;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Body.Systems;
using Content.Server.Disposal.Unit;
using Content.Shared._DV.Psionics.Components.PsionicPowers;
using Content.Shared._DV.Psionics.Events.PowerActionEvents;
using Content.Shared._DV.Psionics.Systems.PsionicPowers;
using Content.Shared.Atmos;
using Content.Shared.Body.Components;
using Content.Shared.Mech.Components;
using Content.Shared.Medical.Cryogenics;
using Content.Shared.Mindshield.Components;
using Content.Shared.Popups;
using Content.Shared.Storage.Components;
namespace Content.Server._DV.Psionics.Systems.PsionicPowers;
public sealed class TelegnosisPowerSystem : SharedTelegnosisPowerSystem
{
[Dependency] private readonly AtmosphereSystem _atmos = default!;
[Dependency] private readonly SharedMindSwapPowerSystem _mindSwap = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<TelegnosisPowerComponent, InhaleLocationEvent>(OnInhaleLocation, after: [typeof(InsideCryoPodComponent), typeof(InternalsComponent), typeof(BeingDisposedComponent), typeof(InsideEntityStorageComponent), typeof(MechPilotComponent)]);
}
// This needs to be here on serverside, because mindswap CANNOT be predicted.
// The logic for transferring minds is server-side only. If we don't put this here, it'll look bad for the person.
protected override void OnPowerUsed(Entity<TelegnosisPowerComponent> psionic, ref TelegnosisPowerActionEvent args)
{
// TODO: Fix this. MindSwapSystem cannot handle popups when called from serverside while the performer is the cause.
if (HasComp<MindShieldComponent>(psionic))
{
Popup.PopupEntity(Loc.GetString("psionic-power-mindswap-own-mindshield"), psionic, psionic, PopupType.SmallCaution);
return;
}
var projection = Spawn(psionic.Comp.Prototype, Transform(psionic).Coordinates);
_transform.AttachToGridOrMap(projection);
if (!_mindSwap.SwapMinds(args.Performer, projection))
{
// If swap didn't work out, delete the spawned projection.
QueueDel(projection);
return;
}
AfterPowerUsed(psionic, args.Performer);
}
private void OnInhaleLocation(Entity<TelegnosisPowerComponent> entity, ref InhaleLocationEvent args)
{
var sensorUid = GetCasterProjection(entity);
if (sensorUid == default)
return;
// Determine the distance to the sensor, this will be used to dilute the amount of air we take in.
var sensorPosition = _transform.GetWorldPosition(sensorUid);
var projectionPosition = _transform.GetWorldPosition(entity);
// A linear curve from 1.0 at 7 tiles away, to 0 at 57 tiles away
var distance = Vector2.Distance(sensorPosition, projectionPosition);
float gasMult = Math.Clamp(1f - (distance - 7f) / 50f, 0f, 1f);
args.Gas = (args.Gas ?? _atmos.GetContainingMixture(entity.Owner, excite: true))?.RemoveVolume(Atmospherics.BreathVolume * gasMult);
if (args.Gas == null)
return;
args.Gas.Volume = Math.Min(args.Gas.Volume, Atmospherics.BreathVolume);
}
}