diff --git a/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Bluespace.cs b/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Bluespace.cs
new file mode 100644
index 00000000000..698f49a112e
--- /dev/null
+++ b/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Bluespace.cs
@@ -0,0 +1,79 @@
+using Content.Shared.Abilities.Psionics;
+using Content.Shared.Actions.Events;
+using Content.Shared.Mobs.Components;
+using System.Linq;
+using System.Numerics;
+using Content.Shared.Database;
+using Robust.Shared.Collections;
+
+namespace Content.Server.Abilities.Psionics;
+
+public sealed partial class AnomalyPowerSystem
+{
+ ///
+ /// This function handles emulating the effects of a "Bluespace Anomaly", using the caster as the "Anomaly",
+ /// while substituting their Psionic casting stats for "Severity and Stability".
+ /// Essentially, scramble the location of entities near the caster(possibly to include the caster).
+ ///
+ private void DoBluespaceAnomalyEffects(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args, bool overcharged = false)
+ {
+ if (args.Bluespace is null)
+ return;
+
+ if (overcharged)
+ BluespaceSupercrit(uid, component, args);
+ else BluespacePulse(uid, component, args);
+ }
+
+ private void BluespaceSupercrit(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args)
+ {
+ var xform = Transform(uid);
+ var mapPos = _xform.GetWorldPosition(xform);
+ var radius = args.Bluespace!.Value.SupercriticalTeleportRadius * component.CurrentAmplification;
+ var gridBounds = new Box2(mapPos - new Vector2(radius, radius), mapPos + new Vector2(radius, radius));
+ var mobs = new HashSet>();
+ _lookup.GetEntitiesInRange(xform.Coordinates, args.Bluespace!.Value.MaxShuffleRadius, mobs);
+ foreach (var comp in mobs)
+ {
+ if (args.Bluespace!.Value.SupercritTeleportsCaster && comp.Owner == uid)
+ continue;
+
+ var ent = comp.Owner;
+ var randomX = _random.NextFloat(gridBounds.Left, gridBounds.Right);
+ var randomY = _random.NextFloat(gridBounds.Bottom, gridBounds.Top);
+
+ var pos = new Vector2(randomX, randomY);
+
+ _adminLogger.Add(LogType.Teleport, $"{ToPrettyString(ent)} has been teleported to {pos} by the supercritical {ToPrettyString(uid)} at {mapPos}");
+
+ _xform.SetWorldPosition(ent, pos);
+ _audio.PlayPvs(args.Bluespace!.Value.TeleportSound, ent);
+ }
+ }
+
+ private void BluespacePulse(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args)
+ {
+ var xformQuery = GetEntityQuery();
+ var xform = xformQuery.GetComponent(uid);
+ var range = args.Bluespace!.Value.MaxShuffleRadius * component.CurrentAmplification;
+ var mobs = new HashSet>();
+ _lookup.GetEntitiesInRange(xform.Coordinates, range, mobs);
+ var allEnts = new ValueList(mobs.Select(m => m.Owner)) { uid };
+ var coords = new ValueList();
+ foreach (var ent in allEnts)
+ {
+ if (args.Bluespace!.Value.PulseTeleportsCaster && ent == uid
+ || !xformQuery.TryGetComponent(ent, out var allXform))
+ continue;
+
+ coords.Add(_xform.GetWorldPosition(allXform));
+ }
+
+ _random.Shuffle(coords);
+ for (var i = 0; i < allEnts.Count; i++)
+ {
+ _adminLogger.Add(LogType.Teleport, $"{ToPrettyString(allEnts[i])} has been shuffled to {coords[i]} by the {ToPrettyString(uid)} at {xform.Coordinates}");
+ _xform.SetWorldPosition(allEnts[i], coords[i]);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Electricity.cs b/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Electricity.cs
new file mode 100644
index 00000000000..3f494aafb10
--- /dev/null
+++ b/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Electricity.cs
@@ -0,0 +1,39 @@
+using Content.Shared.Abilities.Psionics;
+using Content.Shared.Actions.Events;
+
+namespace Content.Server.Abilities.Psionics;
+
+public sealed partial class AnomalyPowerSystem
+{
+ ///
+ /// This function handles emulating the effects of a "Electrical Anomaly", using the caster as the "Anomaly",
+ /// while substituting their Psionic casting stats for "Severity and Stability".
+ /// This fires lightning bolts at random entities near the caster.
+ ///
+ private void DoElectricityAnomalyEffects(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args, bool overcharged = false)
+ {
+ if (args.Electricity is null)
+ return;
+
+ if (overcharged)
+ ElectricitySupercrit(uid, component, args);
+ else ElectricityPulse(uid, component, args);
+ }
+
+ private void ElectricitySupercrit(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args)
+ {
+ var range = args.Electricity!.Value.MaxElectrocuteRange * component.CurrentAmplification;
+
+ _emp.EmpPulse(_xform.GetMapCoordinates(uid), range, args.Electricity!.Value.EmpEnergyConsumption, args.Electricity!.Value.EmpDisabledDuration);
+ _lightning.ShootRandomLightnings(uid, range, args.Electricity!.Value.MaxBoltCount * (int) component.CurrentAmplification, arcDepth: (int) component.CurrentDampening);
+ }
+
+ private void ElectricityPulse(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args)
+ {
+ var range = args.Electricity!.Value.MaxElectrocuteRange * component.CurrentAmplification;
+
+ int boltCount = (int) MathF.Floor(MathHelper.Lerp(args.Electricity!.Value.MinBoltCount, args.Electricity!.Value.MaxBoltCount, component.CurrentAmplification));
+
+ _lightning.ShootRandomLightnings(uid, range, boltCount);
+ }
+}
\ No newline at end of file
diff --git a/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.EntitySpawn.cs b/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.EntitySpawn.cs
new file mode 100644
index 00000000000..8d4898ed8d6
--- /dev/null
+++ b/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.EntitySpawn.cs
@@ -0,0 +1,79 @@
+using Content.Shared.Abilities.Psionics;
+using Content.Shared.Actions.Events;
+using Content.Shared.Random.Helpers;
+using Robust.Shared.Random;
+using Content.Shared.Anomaly.Effects.Components;
+using Robust.Shared.Map.Components;
+
+namespace Content.Server.Abilities.Psionics;
+
+public sealed partial class AnomalyPowerSystem
+{
+ private const string NoGrid = "entity-anomaly-no-grid";
+
+ ///
+ /// This function handles emulating the effects of an "Entity Anomaly", using the caster as the "Anomaly",
+ /// while substituting their Psionic casting stats for "Severity and Stability".
+ /// Essentially, spawn entities on random tiles in a radius around the caster.
+ ///
+ private void DoEntityAnomalyEffects(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args, bool overcharged = false)
+ {
+ if (args.EntitySpawnEntries is null)
+ return;
+
+ if (Transform(uid).GridUid is null)
+ {
+ _popup.PopupEntity(Loc.GetString(NoGrid), uid, uid);
+ return;
+ }
+
+ if (overcharged)
+ EntitySupercrit(uid, component, args);
+ else EntityPulse(uid, component, args);
+ }
+
+ private void EntitySupercrit(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args)
+ {
+ foreach (var entry in args.EntitySpawnEntries!)
+ {
+ if (!entry.Settings.SpawnOnSuperCritical)
+ continue;
+
+ SpawnEntities(uid, component, entry);
+ }
+ }
+
+ private void EntityPulse(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args)
+ {
+ if (args.EntitySpawnEntries is null)
+ return;
+
+ foreach (var entry in args.EntitySpawnEntries!)
+ {
+ if (!entry.Settings.SpawnOnPulse)
+ continue;
+
+ SpawnEntities(uid, component, entry);
+ }
+ }
+
+ private void SpawnEntities(EntityUid uid, PsionicComponent component, EntitySpawnSettingsEntry entry)
+ {
+ if (!TryComp(Transform(uid).GridUid, out var grid))
+ return;
+
+ var tiles = _anomalySystem.GetSpawningPoints(uid,
+ component.CurrentDampening,
+ component.CurrentAmplification,
+ entry.Settings,
+ _glimmerSystem.Glimmer / 1000,
+ component.CurrentAmplification,
+ component.CurrentAmplification);
+
+ if (tiles is null)
+ return;
+
+ foreach (var tileref in tiles)
+ Spawn(_random.Pick(entry.Spawns), _mapSystem.ToCenterCoordinates(tileref, grid));
+ }
+}
\ No newline at end of file
diff --git a/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Explosion.cs b/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Explosion.cs
new file mode 100644
index 00000000000..06501afa71b
--- /dev/null
+++ b/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Explosion.cs
@@ -0,0 +1,52 @@
+using Content.Shared.Abilities.Psionics;
+using Content.Shared.Actions.Events;
+
+namespace Content.Server.Abilities.Psionics;
+
+public sealed partial class AnomalyPowerSystem
+{
+ ///
+ /// This function handles emulating the effects of a "Explosion Anomaly", using the caster as the "Anomaly",
+ /// while substituting their Psionic casting stats for "Severity and Stability".
+ /// Generates an explosion centered on the caster.
+ ///
+ private void DoExplosionAnomalyEffects(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args, bool overcharged = false)
+ {
+ if (args.Explosion is null)
+ return;
+
+ if (overcharged)
+ ExplosionSupercrit(uid, component, args);
+ else ExplosionPulse(uid, component, args);
+ }
+
+ private void ExplosionSupercrit(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args)
+ {
+ if (args.Explosion!.Value.SupercritExplosionPrototype is null)
+ return;
+
+ var explosion = args.Explosion!.Value;
+ _boom.QueueExplosion(
+ uid,
+ explosion.SupercritExplosionPrototype,
+ explosion.SupercritTotalIntensity * component.CurrentAmplification,
+ explosion.SupercritDropoff / component.CurrentDampening,
+ explosion.SupercritMaxTileIntensity * component.CurrentDampening
+ );
+ }
+
+ private void ExplosionPulse(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args)
+ {
+ if (args.Explosion!.Value.ExplosionPrototype is null)
+ return;
+
+ var explosion = args.Explosion!.Value;
+ _boom.QueueExplosion(
+ uid,
+ explosion.ExplosionPrototype,
+ explosion.TotalIntensity * component.CurrentAmplification,
+ explosion.Dropoff / component.CurrentDampening,
+ explosion.MaxTileIntensity * component.CurrentDampening
+ );
+ }
+}
\ No newline at end of file
diff --git a/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.GasProducer.cs b/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.GasProducer.cs
new file mode 100644
index 00000000000..e0dbfd2d1fe
--- /dev/null
+++ b/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.GasProducer.cs
@@ -0,0 +1,110 @@
+using Content.Shared.Abilities.Psionics;
+using Content.Shared.Actions.Events;
+using Robust.Shared.Map.Components;
+using System.Linq;
+using System.Numerics;
+
+namespace Content.Server.Abilities.Psionics;
+
+public sealed partial class AnomalyPowerSystem
+{
+ private void DoGasProducerAnomalyEffects(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args, bool overcharged = false)
+ {
+ if (args.Gas is not null)
+ return;
+
+ if (overcharged)
+ GasProducerSupercrit(uid, component, args);
+ else GasProducerPulse(uid, component, args);
+ }
+
+ private void GasProducerSupercrit(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args)
+ {
+ var xform = Transform(uid);
+ if (!TryComp(xform.GridUid, out var grid))
+ return;
+
+ var gas = args.Gas!.Value.SupercritReleasedGas;
+ var mols = args.Gas!.Value.SupercritMoleAmount * component.CurrentAmplification;
+ var radius = args.Gas!.Value.SupercritSpawnRadius * component.CurrentAmplification;
+ var count = args.Gas!.Value.SupercritTileCount * component.CurrentDampening;
+ var temp = args.Gas!.Value.SupercritTempChange * component.CurrentDampening;
+ var localpos = xform.Coordinates.Position;
+ var tilerefs = grid.GetLocalTilesIntersecting(
+ new Box2(localpos + new Vector2(-radius, -radius), localpos + new Vector2(radius, radius))).ToArray();
+
+ if (tilerefs.Length == 0)
+ return;
+
+ var mixture = _atmosphere.GetTileMixture((uid, xform), true);
+ if (mixture != null)
+ {
+ mixture.AdjustMoles(gas, mols);
+ mixture.Temperature += temp;
+ }
+
+ if (count == 0)
+ return;
+
+ _random.Shuffle(tilerefs);
+ var amountCounter = 0;
+ foreach (var tileref in tilerefs)
+ {
+ var mix = _atmosphere.GetTileMixture(xform.GridUid, xform.MapUid, tileref.GridIndices, true);
+ amountCounter++;
+ if (mix is not { })
+ continue;
+
+ mix.AdjustMoles(gas, mols);
+ mix.Temperature += temp;
+
+ if (amountCounter >= count)
+ return;
+ }
+ }
+
+ private void GasProducerPulse(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args)
+ {
+ var xform = Transform(uid);
+ if (!TryComp(xform.GridUid, out var grid))
+ return;
+
+ var gas = args.Gas!.Value.ReleasedGas;
+ var mols = args.Gas!.Value.MoleAmount * component.CurrentAmplification;
+ var radius = args.Gas!.Value.SpawnRadius * component.CurrentAmplification;
+ var count = args.Gas!.Value.TileCount * component.CurrentDampening;
+ var temp = args.Gas!.Value.TempChange * component.CurrentDampening;
+ var localpos = xform.Coordinates.Position;
+ var tilerefs = grid.GetLocalTilesIntersecting(
+ new Box2(localpos + new Vector2(-radius, -radius), localpos + new Vector2(radius, radius))).ToArray();
+
+ if (tilerefs.Length == 0)
+ return;
+
+ var mixture = _atmosphere.GetTileMixture((uid, xform), true);
+ if (mixture != null)
+ {
+ mixture.AdjustMoles(gas, mols);
+ mixture.Temperature += temp;
+ }
+
+ if (count == 0)
+ return;
+
+ _random.Shuffle(tilerefs);
+ var amountCounter = 0;
+ foreach (var tileref in tilerefs)
+ {
+ var mix = _atmosphere.GetTileMixture(xform.GridUid, xform.MapUid, tileref.GridIndices, true);
+ amountCounter++;
+ if (mix is not { })
+ continue;
+
+ mix.AdjustMoles(gas, mols);
+ mix.Temperature += temp;
+
+ if (amountCounter >= count)
+ return;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Gravity.cs b/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Gravity.cs
new file mode 100644
index 00000000000..532cb846d4b
--- /dev/null
+++ b/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Gravity.cs
@@ -0,0 +1,78 @@
+using Content.Shared.Abilities.Psionics;
+using Content.Shared.Actions.Events;
+using Robust.Shared.Physics.Components;
+using Content.Shared.Physics;
+using System.Linq;
+using Robust.Shared.Map;
+using Robust.Shared.Map.Components;
+
+namespace Content.Server.Abilities.Psionics;
+
+public sealed partial class AnomalyPowerSystem
+{
+ private void DoGravityAnomalyEffects(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args, bool overcharged = false)
+ {
+ if (args.Gravity is null)
+ return;
+
+ if (overcharged)
+ GravitySupercrit(uid, component, args);
+ else GravityPulse(uid, component, args);
+ }
+
+ private void GravitySupercrit(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args)
+ {
+ var xform = Transform(uid);
+ if (!TryComp(xform.GridUid, out MapGridComponent? grid))
+ return;
+
+ var gravity = args.Gravity!.Value;
+ var worldPos = _xform.GetWorldPosition(xform);
+ var tileref = _mapSystem.GetTilesIntersecting(
+ xform.GridUid.Value,
+ grid,
+ new Circle(worldPos, gravity.SpaceRange))
+ .ToArray();
+
+ var tiles = tileref.Select(t => (t.GridIndices, Tile.Empty)).ToList();
+ _mapSystem.SetTiles(xform.GridUid.Value, grid, tiles);
+
+ var range = gravity.MaxThrowRange * component.CurrentDampening;
+ var strength = gravity.MaxThrowStrength * component.CurrentAmplification;
+ var lookup = _lookup.GetEntitiesInRange(uid, range, LookupFlags.Dynamic | LookupFlags.Sundries);
+ var xformQuery = GetEntityQuery();
+ var physQuery = GetEntityQuery();
+
+ foreach (var ent in lookup)
+ {
+ if (physQuery.TryGetComponent(ent, out var phys)
+ && (phys.CollisionMask & (int) CollisionGroup.GhostImpassable) != 0)
+ continue;
+
+ var foo = _xform.GetWorldPosition(ent, xformQuery) - worldPos;
+ _throwing.TryThrow(ent, foo * 5, strength, uid, 0);
+ }
+ }
+
+ private void GravityPulse(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args)
+ {
+ var gravity = args.Gravity!.Value;
+ var xform = Transform(uid);
+ var range = gravity.MaxThrowRange * component.CurrentDampening;
+ var strength = gravity.MaxThrowStrength * component.CurrentAmplification;
+ var lookup = _lookup.GetEntitiesInRange(uid, range, LookupFlags.Dynamic | LookupFlags.Sundries);
+ var xformQuery = GetEntityQuery();
+ var worldPos = _xform.GetWorldPosition(xform, xformQuery);
+ var physQuery = GetEntityQuery();
+
+ foreach (var ent in lookup)
+ {
+ if (physQuery.TryGetComponent(ent, out var phys)
+ && (phys.CollisionMask & (int) CollisionGroup.GhostImpassable) != 0)
+ continue;
+
+ var foo = _xform.GetWorldPosition(ent, xformQuery) - worldPos;
+ _throwing.TryThrow(ent, foo * 10, strength, uid, 0);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Injection.cs b/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Injection.cs
new file mode 100644
index 00000000000..e2b11392718
--- /dev/null
+++ b/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Injection.cs
@@ -0,0 +1,78 @@
+using Content.Shared.Abilities.Psionics;
+using Content.Shared.Actions.Events;
+using Content.Shared.Chemistry.Components.SolutionManager;
+using System.Linq;
+
+namespace Content.Server.Abilities.Psionics;
+
+public sealed partial class AnomalyPowerSystem
+{
+ private EntityQuery _injectableQuery;
+ private void DoInjectionAnomalyEffects(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args, bool overcharged = false)
+ {
+ if (args.Injection is null)
+ return;
+
+ if (overcharged)
+ InjectionSupercrit(uid, component, args);
+ else InjectionPulse(uid, component, args);
+ }
+
+ private void InjectionSupercrit(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args)
+ {
+ var injection = args.Injection!.Value;
+ var injectRadius = injection.SuperCriticalInjectRadius * component.CurrentAmplification;
+ var maxInject = injection.SuperCriticalSolutionInjection * component.CurrentDampening;
+
+ if (!_solutionContainer.TryGetSolution(uid, injection.Solution, out _, out var sol))
+ return;
+
+ //We get all the entity in the radius into which the reagent will be injected.
+ var xformQuery = GetEntityQuery();
+ var xform = xformQuery.GetComponent(uid);
+ var allEnts = _lookup.GetEntitiesInRange(_xform.GetMapCoordinates(uid), injectRadius)
+ .Select(x => x.Owner).ToList();
+
+ //for each matching entity found
+ foreach (var ent in allEnts)
+ {
+ if (!_solutionContainer.TryGetInjectableSolution(ent, out var injectable, out _)
+ || !_injectableQuery.TryGetComponent(ent, out var injEnt)
+ || !_solutionContainer.TryTransferSolution(injectable.Value, sol, maxInject))
+ continue;
+
+ //Spawn Effect
+ var uidXform = Transform(ent);
+ Spawn(injection.VisualEffectPrototype, uidXform.Coordinates);
+ }
+ }
+
+ private void InjectionPulse(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args)
+ {
+ var injection = args.Injection!.Value;
+ var injectRadius = injection.InjectRadius * component.CurrentAmplification;
+ var maxInject = injection.MaxSolutionInjection * component.CurrentDampening;
+
+ if (!_solutionContainer.TryGetSolution(uid, injection.Solution, out _, out var sol))
+ return;
+
+ //We get all the entity in the radius into which the reagent will be injected.
+ var xformQuery = GetEntityQuery();
+ var xform = xformQuery.GetComponent(uid);
+ var allEnts = _lookup.GetEntitiesInRange(_xform.GetMapCoordinates(uid), injectRadius)
+ .Select(x => x.Owner).ToList();
+
+ //for each matching entity found
+ foreach (var ent in allEnts)
+ {
+ if (!_solutionContainer.TryGetInjectableSolution(ent, out var injectable, out _)
+ || !_injectableQuery.TryGetComponent(ent, out var injEnt)
+ || !_solutionContainer.TryTransferSolution(injectable.Value, sol, maxInject))
+ continue;
+
+ //Spawn Effect
+ var uidXform = Transform(ent);
+ Spawn(injection.VisualEffectPrototype, uidXform.Coordinates);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Puddle.cs b/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Puddle.cs
new file mode 100644
index 00000000000..a53b5e4930f
--- /dev/null
+++ b/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Puddle.cs
@@ -0,0 +1,38 @@
+using Content.Shared.Abilities.Psionics;
+using Content.Shared.Actions.Events;
+
+namespace Content.Server.Abilities.Psionics;
+
+public sealed partial class AnomalyPowerSystem
+{
+ private void DoPuddleAnomalyEffects(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args, bool overcharged = false)
+ {
+ if (args.Puddle is null)
+ return;
+
+ if (overcharged)
+ PuddleSupercrit(uid, args);
+ else PuddlePulse(uid, component, args);
+ }
+
+ private void PuddleSupercrit(EntityUid uid, AnomalyPowerActionEvent args)
+ {
+ var puddle = args.Puddle!.Value;
+ if (!_solutionContainer.TryGetSolution(uid, puddle.Solution, out _, out var sol))
+ return;
+
+ var xform = Transform(uid);
+ _puddle.TrySpillAt(xform.Coordinates, sol, out _);
+ }
+
+ private void PuddlePulse(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args)
+ {
+ var puddle = args.Puddle!.Value;
+ if (!_solutionContainer.TryGetSolution(uid, puddle.Solution, out var sol, out _))
+ return;
+
+ var xform = Transform(uid);
+ var puddleSol = _solutionContainer.SplitSolution(sol.Value, puddle.MaxPuddleSize * component.CurrentAmplification);
+ _puddle.TrySplashSpillAt(uid, xform.Coordinates, puddleSol, out _);
+ }
+}
\ No newline at end of file
diff --git a/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Pyroclastic.cs b/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Pyroclastic.cs
new file mode 100644
index 00000000000..0ff6fc28b83
--- /dev/null
+++ b/Content.Server/Abilities/Psionics/Abilities/AnomalyPowerSystem.Pyroclastic.cs
@@ -0,0 +1,49 @@
+using Content.Shared.Abilities.Psionics;
+using Content.Shared.Actions.Events;
+using Content.Server.Atmos.Components;
+using Robust.Shared.Map;
+
+namespace Content.Server.Abilities.Psionics;
+
+public sealed partial class AnomalyPowerSystem
+{
+ private void DoPyroclasticAnomalyEffects(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args, bool overcharged = false)
+ {
+ if (args.Pyroclastic is null)
+ return;
+
+ if (overcharged)
+ PyroclasticSupercrit(uid, component, args);
+ else PyroclasticPulse(uid, component, args);
+ }
+
+ private void PyroclasticSupercrit(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args)
+ {
+ var pyroclastic = args.Pyroclastic!.Value;
+ var xform = Transform(uid);
+ var ignitionRadius = pyroclastic.SupercritMaximumIgnitionRadius * component.CurrentAmplification;
+ IgniteNearby(uid, xform.Coordinates, component.CurrentAmplification, ignitionRadius);
+ }
+
+ private void PyroclasticPulse(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args)
+ {
+ var pyroclastic = args.Pyroclastic!.Value;
+ var xform = Transform(uid);
+ var ignitionRadius = pyroclastic.MaximumIgnitionRadius * component.CurrentAmplification;
+ IgniteNearby(uid, xform.Coordinates, component.CurrentAmplification, ignitionRadius);
+ }
+
+ private void IgniteNearby(EntityUid uid, EntityCoordinates coordinates, float severity, float radius)
+ {
+ var flammables = new HashSet>();
+ _lookup.GetEntitiesInRange(coordinates, radius, flammables);
+
+ foreach (var flammable in flammables)
+ {
+ var ent = flammable.Owner;
+ var stackAmount = 1 + (int) (severity / 0.15f);
+ _flammable.AdjustFireStacks(ent, stackAmount, flammable);
+ _flammable.Ignite(ent, uid, flammable);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Content.Server/Abilities/Psionics/AnomalyPowerSystem.cs b/Content.Server/Abilities/Psionics/AnomalyPowerSystem.cs
index 1548e4e2f3e..388a40a93a0 100644
--- a/Content.Server/Abilities/Psionics/AnomalyPowerSystem.cs
+++ b/Content.Server/Abilities/Psionics/AnomalyPowerSystem.cs
@@ -1,19 +1,24 @@
using Content.Shared.Abilities.Psionics;
using Content.Shared.Actions.Events;
using Content.Shared.Psionics.Glimmer;
-using Content.Shared.Random.Helpers;
using Robust.Shared.Random;
-using Content.Shared.Anomaly.Effects.Components;
-using Robust.Shared.Map.Components;
using Content.Shared.Anomaly;
using Robust.Shared.Audio.Systems;
using Content.Shared.Actions;
using Content.Shared.Damage;
using Content.Server.Popups;
+using Content.Shared.Administration.Logs;
+using Content.Server.Lightning;
+using Content.Server.Emp;
+using Content.Server.Explosion.EntitySystems;
+using Content.Server.Atmos.EntitySystems;
+using Content.Shared.Throwing;
+using Content.Server.Chemistry.Containers.EntitySystems;
+using Content.Server.Fluids.EntitySystems;
namespace Content.Server.Abilities.Psionics;
-public sealed class AnomalyPowerSystem : EntitySystem
+public sealed partial class AnomalyPowerSystem : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly GlimmerSystem _glimmerSystem = default!;
@@ -24,6 +29,18 @@ public sealed class AnomalyPowerSystem : EntitySystem
[Dependency] private readonly SharedActionsSystem _actions = default!;
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly PopupSystem _popup = default!;
+ [Dependency] private readonly EntityLookupSystem _lookup = default!;
+ [Dependency] private readonly SharedTransformSystem _xform = default!;
+ [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
+ [Dependency] private readonly LightningSystem _lightning = default!;
+ [Dependency] private readonly EmpSystem _emp = default!;
+ [Dependency] private readonly ExplosionSystem _boom = default!;
+ [Dependency] private readonly AtmosphereSystem _atmosphere = default!;
+ [Dependency] private readonly ThrowingSystem _throwing = default!;
+ [Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
+ [Dependency] private readonly PuddleSystem _puddle = default!;
+ [Dependency] private readonly FlammableSystem _flammable = default!;
+
public override void Initialize()
{
base.Initialize();
@@ -37,20 +54,18 @@ private void OnPowerUsed(EntityUid uid, PsionicComponent component, AnomalyPower
return;
var overcharged = _glimmerSystem.Glimmer * component.CurrentAmplification
- > Math.Min(args.SupercriticalThreshold * component.CurrentDampening, args.MaxSupercriticalThreshold);
+ > Math.Min(args.Settings.SupercriticalThreshold * component.CurrentDampening, args.Settings.MaxSupercriticalThreshold);
- // I already hate this, so much.
- //DoBluespaceAnomalyEffects(uid, component, args, overcharged);
- //DoElectricityAnomalyEffects(uid, component, args, overcharged);
+ // Behold the wall of nullable logic gates.
+ DoBluespaceAnomalyEffects(uid, component, args, overcharged);
+ DoElectricityAnomalyEffects(uid, component, args, overcharged);
DoEntityAnomalyEffects(uid, component, args, overcharged);
- //DoExplosionAnomalyEffects(uid, component, args, overcharged);
- //DoGasProducerAnomalyEffects(uid, component, args, overcharged);
- //DoGravityAnomalyEffects(uid, component, args, overcharged);
- //DoInjectionAnomalyEffects(uid, component, args, overcharged);
- //DoPuddleCreateAnomalyEffects(uid, component, args, overcharged);
- //DoPyroclasticAnomalyEffects(uid, component, args, overcharged);
- //DoTemperatureAnomalyEffects(uid, component, args, overcharged);
-
+ DoExplosionAnomalyEffects(uid, component, args, overcharged);
+ DoGasProducerAnomalyEffects(uid, component, args, overcharged);
+ DoGravityAnomalyEffects(uid, component, args, overcharged);
+ DoInjectionAnomalyEffects(uid, component, args, overcharged);
+ DoPuddleAnomalyEffects(uid, component, args, overcharged);
+ DoPyroclasticAnomalyEffects(uid, component, args, overcharged);
DoAnomalySounds(uid, component, args, overcharged);
DoGlimmerEffects(uid, component, args, overcharged);
@@ -60,87 +75,45 @@ private void OnPowerUsed(EntityUid uid, PsionicComponent component, AnomalyPower
args.Handled = true;
}
- public void DoEntityAnomalyEffects(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args, bool overcharged)
- {
- if (args.EntitySpawnEntries is null)
- return;
-
- if (overcharged)
- foreach (var entry in args.EntitySpawnEntries)
- {
- if (!entry.Settings.SpawnOnSuperCritical)
- continue;
-
- SpawnEntities(uid, component, entry);
- }
- else foreach (var entry in args.EntitySpawnEntries)
- {
- if (!entry.Settings.SpawnOnPulse)
- continue;
-
- SpawnEntities(uid, component, entry);
- }
- }
-
- public void SpawnEntities(EntityUid uid, PsionicComponent component, EntitySpawnSettingsEntry entry)
- {
- if (!TryComp(Transform(uid).GridUid, out var grid))
- return;
-
- var tiles = _anomalySystem.GetSpawningPoints(uid,
- component.CurrentDampening,
- component.CurrentAmplification,
- entry.Settings,
- _glimmerSystem.Glimmer / 1000,
- component.CurrentAmplification,
- component.CurrentAmplification);
-
- if (tiles is null)
- return;
-
- foreach (var tileref in tiles)
- Spawn(_random.Pick(entry.Spawns), _mapSystem.ToCenterCoordinates(tileref, grid));
- }
-
public void DoAnomalySounds(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args, bool overcharged = false)
{
- if (overcharged && args.SupercriticalSound is not null)
+ if (overcharged && args.Settings.SupercriticalSound is not null)
{
- _audio.PlayPvs(args.SupercriticalSound, uid);
+ _audio.PlayPvs(args.Settings.SupercriticalSound, uid);
return;
}
- if (args.PulseSound is null
- || _glimmerSystem.Glimmer < args.GlimmerSoundThreshold * component.CurrentDampening)
+ if (args.Settings.PulseSound is null
+ || _glimmerSystem.Glimmer < args.Settings.GlimmerSoundThreshold * component.CurrentDampening)
return;
- _audio.PlayEntity(args.PulseSound, uid, uid);
+ _audio.PlayEntity(args.Settings.PulseSound, uid, uid);
}
public void DoGlimmerEffects(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args, bool overcharged = false)
{
- var minGlimmer = (int) Math.Round(MathF.MinMagnitude(args.MinGlimmer, args.MaxGlimmer)
- * (overcharged ? args.SupercriticalGlimmerMultiplier : 1)
+ var minGlimmer = (int) Math.Round(MathF.MinMagnitude(args.Settings.MinGlimmer, args.Settings.MaxGlimmer)
+ * (overcharged ? args.Settings.SupercriticalGlimmerMultiplier : 1)
* component.CurrentAmplification - component.CurrentDampening);
- var maxGlimmer = (int) Math.Round(MathF.MaxMagnitude(args.MinGlimmer, args.MaxGlimmer)
- * (overcharged ? args.SupercriticalGlimmerMultiplier : 1)
+ var maxGlimmer = (int) Math.Round(MathF.MaxMagnitude(args.Settings.MinGlimmer, args.Settings.MaxGlimmer)
+ * (overcharged ? args.Settings.SupercriticalGlimmerMultiplier : 1)
* component.CurrentAmplification - component.CurrentDampening);
- _psionics.LogPowerUsed(uid, args.PowerName, minGlimmer, maxGlimmer);
+ _psionics.LogPowerUsed(uid, args.Settings.PowerName, minGlimmer, maxGlimmer);
}
public void DoOverchargedEffects(EntityUid uid, PsionicComponent component, AnomalyPowerActionEvent args)
{
- if (args.OverchargeFeedback is not null
- && Loc.TryGetString(args.OverchargeFeedback, out var popup))
+ if (args.Settings.OverchargeFeedback is not null
+ && Loc.TryGetString(args.Settings.OverchargeFeedback, out var popup))
_popup.PopupEntity(popup, uid, uid);
- if (args.OverchargeRecoil is not null
+ if (args.Settings.OverchargeRecoil is not null
&& TryComp(uid, out var damageable))
- _damageable.TryChangeDamage(uid, args.OverchargeRecoil / component.CurrentDampening, true, true, damageable, uid);
+ _damageable.TryChangeDamage(uid, args.Settings.OverchargeRecoil / component.CurrentDampening, true, true, damageable, uid);
- if (args.OverchargeCooldown > 0)
+ if (args.Settings.OverchargeCooldown > 0)
foreach (var action in component.Actions)
- _actions.SetCooldown(action.Value, TimeSpan.FromSeconds(args.OverchargeCooldown / component.CurrentDampening));
+ _actions.SetCooldown(action.Value, TimeSpan.FromSeconds(args.Settings.OverchargeCooldown / component.CurrentDampening));
}
}
diff --git a/Content.Shared/Actions/Events/AnomalyPowerActionEvent.cs b/Content.Shared/Actions/Events/AnomalyPowerActionEvent.cs
index c5a792b4798..0146f57ffab 100644
--- a/Content.Shared/Actions/Events/AnomalyPowerActionEvent.cs
+++ b/Content.Shared/Actions/Events/AnomalyPowerActionEvent.cs
@@ -1,84 +1,378 @@
using Content.Shared.Anomaly.Effects.Components;
+using Content.Shared.Atmos;
using Content.Shared.Damage;
using Robust.Shared.Audio;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+using Content.Shared.Explosion;
+using Robust.Shared.Prototypes;
namespace Content.Shared.Actions.Events;
public sealed partial class AnomalyPowerActionEvent : InstantActionEvent
{
+ ///
+ /// Contains settings common to all "Anomalist" Powers.
+ ///
+ [DataField]
+ public AnomalyPowerSettings Settings = default!;
+
+ ///
+ /// Contains settings specific to "Bluespace Anomaly" powers.
+ ///
+ [DataField]
+ public BluespaceAnomalySettings? Bluespace = default!;
+ ///
+ /// Contains settings specific to "Electrical Anomaly" powers.
+ ///
+ [DataField]
+ public ElectricalAnomalySettings? Electricity = default!;
+
+ ///
+ /// What entities will be spawned by this action, using the same arguments as an EntitySpawnAnomalyComponent.
+ ///
[DataField]
+ public List? EntitySpawnEntries;
+
+ ///
+ /// Contains settings specific to "Explosion Anomaly" powers.
+ ///
+ [DataField]
+ public ExplosionAnomalySettings? Explosion = default!;
+
+ ///
+ /// Contains settings specific to "Gas Producer Anomaly" powers.
+ ///
+ [DataField]
+ public GasProducerAnomalySettings? Gas = default!;
+
+ ///
+ /// Contains settings specific to "Gravity Anomaly" powers.
+ ///
+ [DataField]
+ public GravityAnomalySettings? Gravity = default!;
+
+ ///
+ /// Contains settings specific to "Injection Anomaly" powers.
+ ///
+ [DataField]
+ public InjectionAnomalySettings? Injection = default!;
+
+ ///
+ /// Contains settings specific to "Puddle Create Anomaly" powers.
+ ///
+ [DataField]
+ public PuddleAnomalySettings? Puddle = default!;
+
+ ///
+ /// Contains settings specific to "Pyroclastic Anomaly" powers.
+ ///
+ [DataField]
+ public PyroclasticAnomalySettings? Pyroclastic = default!;
+}
+
+[DataRecord]
+public partial record struct AnomalyPowerSettings()
+{
public string PowerName;
///
/// When casting above the Supercritical Threshold, if not 0, this will cause all powers to enter cooldown for the given duration.
///
- [DataField]
public float OverchargeCooldown;
///
/// When casting above the Supercritical Threshold, if not 0, this will deal recoil damage to the caster of the specified amounts.
///
- [DataField]
public DamageSpecifier? OverchargeRecoil;
///
/// When casting above the Supercritical Threshold, play a popup above the caster's head.
///
- [DataField]
public string? OverchargeFeedback;
///
/// The minimum amount of glimmer generated by this power.
///
- [DataField]
public int MinGlimmer;
///
/// The maximum amount of glimmer generated by this power.
///
- [DataField]
public int MaxGlimmer;
///
/// The amount to multiply glimmer generation by when above the Supercritical Threshold
///
- [DataField]
public int SupercriticalGlimmerMultiplier = 1;
///
/// The threshold of glimmer at which this power will play a sound.
///
- [DataField]
public float GlimmerSoundThreshold;
///
/// The glimmer threshold(divided by amplification and multiplied by dampening) at which this power will act as a Supercritical Anomaly.
///
- [DataField]
public float SupercriticalThreshold = 500f;
///
/// The maximum amount Dampening can increase the Supercritical threshold to.
///
- [DataField]
public float MaxSupercriticalThreshold = 800f;
- ///
- /// What entities will be spawned by this action, using the same arguments as an EntitySpawnAnomalyComponent?
- ///
- [DataField]
- public List? EntitySpawnEntries;
-
///
/// The sound to be played upon activating this power(and not Supercritically)
///
- [DataField]
public SoundSpecifier? PulseSound = new SoundCollectionSpecifier("RadiationPulse");
///
/// The sound plays when this power is activated above a Supercritical glimmer threshold
///
- [DataField]
public SoundSpecifier? SupercriticalSound = new SoundCollectionSpecifier("Explosion");
}
+
+[DataRecord]
+public partial record struct BluespaceAnomalySettings()
+{
+ ///
+ /// The maximum radius that the shuffle effect will extend for
+ /// scales with stability
+ ///
+ public float MaxShuffleRadius = 10;
+
+ ///
+ /// Whether or not a standard pulse teleports the caster.
+ ///
+ public bool PulseTeleportsCaster;
+
+ ///
+ /// Whether or not a supercrit teleports the caster.
+ ///
+ public bool SupercritTeleportsCaster;
+
+ ///
+ /// How far the supercritical event can teleport you
+ ///
+ public float SupercriticalTeleportRadius = 50f;
+
+ ///
+ /// The sound played after players are shuffled/teleported around
+ ///
+ public SoundSpecifier TeleportSound = new SoundPathSpecifier("/Audio/Effects/teleport_arrival.ogg");
+}
+
+[DataRecord]
+public partial record struct ElectricalAnomalySettings()
+{
+ ///
+ /// the minimum number of lightning strikes
+ ///
+ public int MinBoltCount = 2;
+
+ ///
+ /// The number of lightning strikes, at the maximum severity of the anomaly
+ ///
+ public int MaxBoltCount = 5;
+
+ ///
+ /// The maximum radius of the passive electrocution effect
+ /// scales with stability
+ ///
+ public float MaxElectrocuteRange = 7f;
+
+ ///
+ /// Energy consumed from devices by the emp pulse upon going supercritical.
+ ///
+ public float EmpEnergyConsumption = 100000f;
+
+ ///
+ /// Duration of devices being disabled by the emp pulse upon going supercritical.
+ ///
+ public float EmpDisabledDuration = 60f;
+}
+
+[DataRecord]
+public partial record struct ExplosionAnomalySettings()
+{
+ ///
+ /// The explosion prototype to spawn
+ ///
+ [DataField(customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string? ExplosionPrototype = default!;
+
+ ///
+ /// The total amount of intensity an explosion can achieve
+ ///
+ public float TotalIntensity = 100f;
+
+ ///
+ /// How quickly does the explosion's power slope? Higher = smaller area and more concentrated damage, lower = larger area and more spread out damage
+ ///
+ public float Dropoff = 10f;
+
+ ///
+ /// How much intensity can be applied per tile?
+ ///
+ public float MaxTileIntensity = 10f;
+
+ ///
+ /// The explosion prototype to spawn on Supercrit
+ ///
+ [DataField(customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string? SupercritExplosionPrototype = default!;
+
+ ///
+ /// The total amount of intensity an explosion can achieve
+ ///
+ public float SupercritTotalIntensity = 100f;
+
+ ///
+ /// How quickly does the explosion's power slope? Higher = smaller area and more concentrated damage, lower = larger area and more spread out damage
+ ///
+ public float SupercritDropoff = 10f;
+
+ ///
+ /// How much intensity can be applied per tile?
+ ///
+ public float SupercritMaxTileIntensity = 10f;
+}
+
+[DataRecord]
+public partial record struct GasProducerAnomalySettings()
+{
+ ///
+ /// The gas to release
+ ///
+ public Gas ReleasedGas = Gas.WaterVapor;
+
+ ///
+ /// The gas to release
+ ///
+ public Gas SupercritReleasedGas = Gas.WaterVapor;
+
+ ///
+ /// The amount of gas released passively
+ ///
+ public float MoleAmount = 1f;
+
+ ///
+ /// The radius of random gas spawns.
+ ///
+ public float SpawnRadius = 3;
+
+ ///
+ /// The number of tiles which will be modified.
+ ///
+ public int TileCount = 1;
+
+ ///
+ /// The the amount the temperature should be modified by (negative for decreasing temp)
+ ///
+ public float TempChange = 0;
+
+ ///
+ /// The amount of gas released when the anomaly reaches max severity
+ ///
+ public float SupercritMoleAmount = 150f;
+
+ ///
+ /// The radius of random gas spawns.
+ ///
+ public float SupercritSpawnRadius = 10;
+
+ ///
+ /// The number of tiles which will be modified.
+ ///
+ public int SupercritTileCount = 10;
+
+ ///
+ /// The the amount the temperature should be modified by (negative for decreasing temp)
+ ///
+ public float SupercritTempChange = 0;
+}
+
+[DataRecord]
+public partial record struct GravityAnomalySettings()
+{
+ ///
+ /// The maximum distance from which the anomaly
+ /// can throw you via a pulse.
+ ///
+ public float MaxThrowRange = 5f;
+
+ ///
+ /// The maximum strength the anomaly
+ /// can throw you via a pulse
+ ///
+ public float MaxThrowStrength = 10;
+
+ ///
+ /// The range around the anomaly that will be spaced on supercritical.
+ ///
+ public float SpaceRange = 3f;
+}
+
+[DataRecord]
+public partial record struct InjectionAnomalySettings()
+{
+ ///
+ /// the maximum amount of injection of a substance into an entity per pulsation
+ /// scales with Severity
+ ///
+ public float MaxSolutionInjection = 15;
+
+ ///
+ /// The maximum amount of injection of a substance into an entity in the supercritical phase
+ ///
+ public float SuperCriticalSolutionInjection = 50;
+
+ ///
+ /// The maximum radius in which the anomaly injects reagents into the surrounding containers.
+ ///
+ public float InjectRadius = 3;
+
+ ///
+ /// The maximum radius in which the anomaly injects reagents into the surrounding containers.
+ ///
+ public float SuperCriticalInjectRadius = 15;
+
+ ///
+ /// The name of the prototype of the special effect that appears above the entities into which the injection was carried out
+ ///
+ public EntProtoId VisualEffectPrototype = "PuddleSparkle";
+
+ ///
+ /// Solution name that can be drained.
+ ///
+ public string Solution { get; set; } = "default";
+}
+
+[DataRecord]
+public partial record struct PuddleAnomalySettings()
+{
+ ///
+ /// The maximum amount of solution that an anomaly can splash out of the storage on the floor during pulsation.
+ /// Scales with Amplification.
+ ///
+ public float MaxPuddleSize = 100;
+
+ ///
+ /// Solution name that can be drained.
+ ///
+ public string Solution { get; set; } = "default";
+}
+
+[DataRecord]
+public partial record struct PyroclasticAnomalySettings()
+{
+ ///
+ /// The maximum distance from which entities will be ignited.
+ ///
+ public float MaximumIgnitionRadius = 5f;
+
+ ///
+ /// The maximum distance from which entities will be ignited on a Supercrit cast.
+ ///
+ public float SupercritMaximumIgnitionRadius = 20f;
+}
diff --git a/Resources/Locale/en-US/psionics/psionic-powers.ftl b/Resources/Locale/en-US/psionics/psionic-powers.ftl
index 43cb1a03f84..9b4d3c49db7 100644
--- a/Resources/Locale/en-US/psionics/psionic-powers.ftl
+++ b/Resources/Locale/en-US/psionics/psionic-powers.ftl
@@ -128,4 +128,5 @@ examine-mindbroken-message =
Eyes unblinking, staring deep into the horizon. {CAPITALIZE($entity)} is a sack of meat pretending it has a soul.
There is nothing behind its gaze, no evidence there can be found of the divine light of creation.
psionic-roll-failed = For a moment, my consciousness expands, yet I feel that it is not enough.
+entity-anomaly-no-grid = There is nowhere for me to conjure beings.
power-overwhelming-power-feedback = {CAPITALIZE($entity)} wields a vast connection to the noƶsphere
diff --git a/Resources/Prototypes/Actions/psionics.yml b/Resources/Prototypes/Actions/psionics.yml
index b929a11c7e6..2e105f3a690 100644
--- a/Resources/Prototypes/Actions/psionics.yml
+++ b/Resources/Prototypes/Actions/psionics.yml
@@ -233,17 +233,18 @@
useDelay: 45
checkCanInteract: false
event: !type:AnomalyPowerActionEvent
- powerName: "Shadeskip"
- overchargeFeedback: "shadeskip-overcharge-feedback"
- overchargeCooldown: 120
- overchargeRecoil:
- groups:
- Burn: -100 #This will be divided by the caster's Dampening.
- minGlimmer: 6
- maxGlimmer: 8
- supercriticalGlimmerMultiplier: 3
- glimmerSoundThreshold: 50
- supercriticalThreshold: 500
+ settings:
+ powerName: "Shadeskip"
+ overchargeFeedback: "shadeskip-overcharge-feedback"
+ overchargeCooldown: 120
+ overchargeRecoil:
+ groups:
+ Burn: -100 #This will be divided by the caster's Dampening.
+ minGlimmer: 6
+ maxGlimmer: 8
+ supercriticalGlimmerMultiplier: 3
+ glimmerSoundThreshold: 50
+ supercriticalThreshold: 500
entitySpawnEntries:
- settings:
spawnOnPulse: true