using Content.Server.Anomaly.Components;
using Content.Server.Power.EntitySystems;
using Content.Server.Research.Components;
using Content.Shared.Anomaly.Components;
using Content.Shared.Mobs;
using Content.Shared.Psionics.Glimmer;
using Content.Shared.Power;
namespace Content.Server.Psionics.Glimmer;
///
/// Handles structures which add/subtract glimmer.
///
public sealed class GlimmerStructuresSystem : EntitySystem
{
[Dependency] private readonly PowerReceiverSystem _powerReceiverSystem = default!;
[Dependency] private readonly GlimmerSystem _glimmerSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent(OnAnomalyVesselPowerChanged);
SubscribeLocalEvent(OnAnomalyPulse);
SubscribeLocalEvent(OnAnomalySupercritical);
SubscribeLocalEvent(OnMobStateChanged);
SubscribeLocalEvent(OnInit);
}
private void OnInit(EntityUid uid, GlimmerSourceComponent component, ComponentStartup args)
{
if (component.ResearchPointGeneration != null)
{
EnsureComp(uid, out var points);
points.PointsPerSecond = component.ResearchPointGeneration.Value;
points.Active = true;
}
}
private void OnAnomalyVesselPowerChanged(EntityUid uid, AnomalyVesselComponent component, ref PowerChangedEvent args)
{
if (TryComp(component.Anomaly, out var glimmerSource))
glimmerSource.Active = args.Powered;
}
private void OnAnomalyPulse(EntityUid uid, GlimmerSourceComponent component, ref AnomalyPulseEvent args)
{
// Anomalies are meant to have GlimmerSource on them with the
// active flag set to false, as they will be set to actively
// generate glimmer when scanned to an anomaly vessel for
// harvesting research points.
//
// It is not a bug that glimmer increases on pulse or
// supercritical with an inactive glimmer source.
//
// However, this will need to be reworked if a distinction
// needs to be made in the future. I suggest a GlimmerAnomaly
// component.
if (TryComp(uid, out var anomaly))
_glimmerSystem.DeltaGlimmerOutput(5f * anomaly.Severity);
}
private void OnAnomalySupercritical(EntityUid uid, GlimmerSourceComponent component, ref AnomalySupercriticalEvent args)
{
_glimmerSystem.DeltaGlimmerOutput(100);
}
private void OnMobStateChanged(EntityUid uid, GlimmerSourceComponent component, ref MobStateChangedEvent args)
{
if (args.NewMobState != MobState.Alive)
component.Active = false;
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var glimmerSources = Count();
foreach (var source in EntityQuery())
{
if (!_powerReceiverSystem.IsPowered(source.Owner)
&& source.RequiresPower)
{
glimmerSources--;
continue;
}
if (!source.Active)
{
glimmerSources--;
continue;
}
source.Accumulator += frameTime;
if (source.Accumulator > source.SecondsPerGlimmer)
{
source.Accumulator -= source.SecondsPerGlimmer;
// https://www.desmos.com/calculator/zjzefpue03
// In Short: 1 prober makes 20 research points. 4 probers makes twice as many points as 1 prober. 9 probers makes 69 points in total between all 9.
// This is then modified by afterwards by GlimmerEquilibrium, to help smooth out the curves. But also, now if you have more drainers than probers, the probers won't generate research!
// Also, this counts things like Anomalies & Glimmer Mites! Which means scientists should be more encouraged to actively hunt mites.
// As a fun novelty, this means that a highly psionic Epistemics department can essentially "Study" their powers for actual research points!
if (source.ResearchPointGeneration != null
&& TryComp(source.Owner, out var research))
research.PointsPerSecond = (int) MathF.Round(
source.ResearchPointGeneration.Value
/ (MathF.Log(glimmerSources, 4) + 1)
* _glimmerSystem.GetGlimmerEquilibriumRatio());
// Shorthand explanation:
// This makes glimmer far more "Swingy", by making both positive and negative glimmer sources scale quite dramatically with glimmer
if (!_glimmerSystem.GetGlimmerEnabled())
return;
var glimmerEquilibrium = GlimmerSystem.GlimmerEquilibrium;
if (source.AddToGlimmer)
{
_glimmerSystem.DeltaGlimmerInput((_glimmerSystem.GlimmerOutput > glimmerEquilibrium
? MathF.Pow(_glimmerSystem.GetGlimmerOutputInteger() - source.GlimmerExponentOffset + glimmerSources, 2) : 1f)
* (_glimmerSystem.GlimmerOutput < glimmerEquilibrium ? _glimmerSystem.GetGlimmerEquilibriumRatio() : 1f));
}
else
{
_glimmerSystem.DeltaGlimmerInput(-(_glimmerSystem.GlimmerOutput > glimmerEquilibrium
? MathF.Pow(_glimmerSystem.GetGlimmerOutputInteger() - source.GlimmerExponentOffset + glimmerSources, 2) : 1f)
* (_glimmerSystem.GlimmerOutput > glimmerEquilibrium ? _glimmerSystem.GetGlimmerEquilibriumRatio() : 1f));
}
}
}
}
}