From 893fad9adbd64d2cab1b19c9356fba37ae399de8 Mon Sep 17 00:00:00 2001
From: portfiend <109661617+portfiend@users.noreply.github.com>
Date: Mon, 13 Apr 2026 15:00:36 -0500
Subject: [PATCH 1/2] basic glimmer system
---
.../Glimmer/EntitySystems/GlimmerSystem.cs | 175 ++++++++++++++++++
.../Components/GlimmerTrackerComponent.cs | 93 ++++++++++
.../EntitySystems/SharedGlimmerSystem.cs | 4 +
.../Entities/Stations/nanotrasen.yml | 1 +
Resources/Prototypes/_DEN/Stations/base.yml | 10 +
5 files changed, 283 insertions(+)
create mode 100644 Content.Server/_DEN/Glimmer/EntitySystems/GlimmerSystem.cs
create mode 100644 Content.Shared/_DEN/Glimmer/Components/GlimmerTrackerComponent.cs
create mode 100644 Content.Shared/_DEN/Glimmer/EntitySystems/SharedGlimmerSystem.cs
create mode 100644 Resources/Prototypes/_DEN/Stations/base.yml
diff --git a/Content.Server/_DEN/Glimmer/EntitySystems/GlimmerSystem.cs b/Content.Server/_DEN/Glimmer/EntitySystems/GlimmerSystem.cs
new file mode 100644
index 00000000000..7c6e11f13fe
--- /dev/null
+++ b/Content.Server/_DEN/Glimmer/EntitySystems/GlimmerSystem.cs
@@ -0,0 +1,175 @@
+using System.Diagnostics.CodeAnalysis;
+using Content.Server.Station.Systems;
+using Content.Shared._DEN.Glimmer.Components;
+using Content.Shared._DEN.Glimmer.EntitySystems;
+using Content.Shared.FixedPoint;
+using JetBrains.Annotations;
+using Robust.Shared.Random;
+
+namespace Content.Server._DEN.Glimmer.EntitySystems;
+
+///
+/// Glimmer is a measure of "noospheric instability", a value that affects both the frequency
+/// and severity of paranormal-themed events. It also affects the level of connection that
+/// psionic users have with the noosphere - this is to say, powers scaling with glimmer.
+///
+public sealed partial class GlimmerTrackerSystem : SharedGlimmerTrackerSystem
+{
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly StationSystem _station = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnGlimmerTrackerStartup);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ private void OnGlimmerTrackerStartup(Entity ent, ref ComponentStartup args)
+ {
+ var comp = ent.Comp;
+ var min = comp.StartingGlimmerLevelRange.X;
+ var max = comp.StartingGlimmerLevelRange.Y;
+ var level = _random.Next(min, max);
+
+ SetGlimmerLevel(ent, level);
+ }
+
+ ///
+ /// Attempt to get the closest applicable glimmer tracker for a given entity.
+ ///
+ ///
+ /// The entity itself will be checked if it is a glimmer tracker, then the entity's station,
+ /// then all trackers will be iterated over to find the closest applicable tracker.
+ ///
+ /// The entity to retrieve the nearest valid glimmer tracker for.
+ /// A glimmer tracker that applies to this entity.
+ /// Whether or not we successfully retrieved a glimmer tracker.
+ private bool TryGetClosestGlimmerTracker(EntityUid uid,
+ [NotNullWhen(true)] out Entity? trackerEnt)
+ {
+ // This entity is a glimmer tracker
+ if (TryComp(uid, out var tracker))
+ {
+ trackerEnt = (uid, tracker);
+ return true;
+ }
+
+ // This is a station map and the station has a glimmer tracker
+ var xform = Transform(uid);
+ if (_station.GetStationInMap(xform.MapID) is EntityUid station
+ && TryComp(station, out tracker))
+ {
+ trackerEnt = (station, tracker);
+ return true;
+ }
+
+ // We get the closest glimmer tracker in the same map
+ var query = EntityQueryEnumerator();
+ (Entity Tracker, float Distance)? closestTracker = null;
+ while (query.MoveNext(out var trackerUid, out tracker))
+ {
+ var ent = (trackerUid, tracker);
+ var trackerXform = Transform(trackerUid);
+
+ if (xform.Coordinates.TryDistance(EntityManager, trackerXform.Coordinates, out var distance)
+ && distance > closestTracker?.Distance)
+ closestTracker = (ent, distance);
+
+ // Global trackers do not need to be in the same map to be detected
+ else if (tracker.Global)
+ closestTracker ??= (ent, float.MaxValue);
+ }
+
+ // May still be null, if there are no trackers at all
+ trackerEnt = closestTracker?.Tracker;
+ return trackerEnt != null;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ private void SetGlimmer(Entity tracker, FixedPoint2 glimmer)
+ {
+ var comp = tracker.Comp;
+ comp.CurrentGlimmer = glimmer;
+
+ // We're adding 1 to this, so that 0 glimmer becomes level 1.
+ var glimmerDivisor = (glimmer + 1) / comp.GlimmerPerLevel;
+ var glimmerLevel = Math.Floor(glimmerDivisor.Float());
+ comp.CurrentGlimmerLevel = (int)glimmerLevel;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ private void SetGlimmerLevel(Entity tracker, int level)
+ {
+ var comp = tracker.Comp;
+ comp.CurrentGlimmerLevel = level;
+
+ var min = (level - 1) * comp.GlimmerPerLevel; // INCLUSIVE
+ var max = level * comp.GlimmerPerLevel; // EXCLUSIVE
+ var newGlimmer = _random.NextFloat(min.Float(), max.Float());
+ comp.CurrentGlimmer = FixedPoint2.New(newGlimmer);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ [PublicAPI]
+ public FixedPoint2 GetCurrentGlimmer(Entity tracker)
+ {
+ return tracker.Comp.CurrentGlimmer;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ [PublicAPI]
+ public FixedPoint2 GetCurrentGlimmer(EntityUid uid)
+ {
+ if (!TryGetClosestGlimmerTracker(uid, out var tracker))
+ return FixedPoint2.Zero;
+
+ return GetCurrentGlimmer(tracker.Value);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ [PublicAPI]
+ public int GetCurrentGlimmerLevel(Entity tracker)
+ {
+ return tracker.Comp.CurrentGlimmerLevel;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ [PublicAPI]
+ public int GetCurrentGlimmerLevel(EntityUid uid)
+ {
+ if (!TryGetClosestGlimmerTracker(uid, out var tracker))
+ return 0;
+
+ return GetCurrentGlimmerLevel(tracker.Value);
+ }
+}
diff --git a/Content.Shared/_DEN/Glimmer/Components/GlimmerTrackerComponent.cs b/Content.Shared/_DEN/Glimmer/Components/GlimmerTrackerComponent.cs
new file mode 100644
index 00000000000..c2527f09132
--- /dev/null
+++ b/Content.Shared/_DEN/Glimmer/Components/GlimmerTrackerComponent.cs
@@ -0,0 +1,93 @@
+using Content.Shared._DEN.Glimmer.EntitySystems;
+using Content.Shared.FixedPoint;
+
+namespace Content.Shared._DEN.Glimmer.Components;
+
+///
+/// A tracker component for measuring glimmer, a measure of current noospheric
+/// instability and influence. Glimmer naturally shifts and fluctuates over time, but
+/// player interference may cause it to shift one way or the other.
+///
+[RegisterComponent]
+[Access(typeof(SharedGlimmerTrackerSystem))]
+public sealed partial class GlimmerTrackerComponent : Component
+{
+ ///
+ /// How many levels of glimmer should we have?
+ ///
+ [DataField]
+ public int GlimmerLevels = 10;
+
+ ///
+ /// How many points of glimmer are in a glimmer level threshold?
+ ///
+ [DataField]
+ public FixedPoint2 GlimmerPerLevel = 100.0f;
+
+ ///
+ /// What level of glimmer should we start with?
+ ///
+ [DataField]
+ public Vector2i StartingGlimmerLevelRange = new(1, 1);
+
+ ///
+ /// An optional limit to what range of glimmer levels we can have.
+ ///
+ ///
+ /// This is meaningful because if GLs runs from 0 to 10, then capping GLs
+ /// between, say, 4 to 7, would ensure constant "moderate-to-high glimmer".
+ ///
+ [DataField]
+ public Vector2i? PossibleGlimmerLevelRange = null;
+
+ ///
+ /// Whether or not glimmer can be changed via gameplay means - random
+ /// fluctuation, events, and player interference.
+ ///
+ ///
+ /// Admins are always capable of changing the current level or amount of glimmer.
+ ///
+ [DataField]
+ public bool AllowGlimmerChange = true;
+
+ ///
+ /// Whether or not this tracker can be used by other maps.
+ ///
+ [DataField]
+ public bool Global = false;
+
+ ///
+ /// Whether or not actions that happen off the map this entity is contained in
+ /// can affect this glimmer tracker.
+ ///
+ ///
+ /// For example: if this is disabled, then psionics usage at CentComm will not
+ /// affect the station glimmer tracker.
+ ///
+ [DataField]
+ public bool OffMapAffectsGlimmer = false;
+
+ ///
+ /// How much glimmer do we currently have?
+ ///
+ ///
+ /// Note that setting glimmer directly is not super meaningful or long-term;
+ /// glimmer frequently fluctuates.
+ ///
+ [ViewVariables(VVAccess.ReadOnly)]
+ public FixedPoint2 CurrentGlimmer = 0;
+
+ ///
+ /// What is our current glimmer level?
+ ///
+ [ViewVariables(VVAccess.ReadOnly)]
+ public int CurrentGlimmerLevel = 1;
+
+ ///
+ /// Glimmer is represented as a range from 0 to (GlimmerLevels * GlimmerPerLevel).
+ /// Assuming there are 10 levels with 100 glimmer each: [0-100) glimmer is level 1,
+ /// [100-200) glimmer is level 2, et cetera. 1000 glimmer is level 10.
+ ///
+ [ViewVariables(VVAccess.ReadOnly)]
+ public FixedPoint2 MaxGlimmer => GlimmerPerLevel * GlimmerLevels;
+}
diff --git a/Content.Shared/_DEN/Glimmer/EntitySystems/SharedGlimmerSystem.cs b/Content.Shared/_DEN/Glimmer/EntitySystems/SharedGlimmerSystem.cs
new file mode 100644
index 00000000000..e1a598610a4
--- /dev/null
+++ b/Content.Shared/_DEN/Glimmer/EntitySystems/SharedGlimmerSystem.cs
@@ -0,0 +1,4 @@
+namespace Content.Shared._DEN.Glimmer.EntitySystems;
+
+public abstract partial class SharedGlimmerTrackerSystem : EntitySystem
+{ }
diff --git a/Resources/Prototypes/Entities/Stations/nanotrasen.yml b/Resources/Prototypes/Entities/Stations/nanotrasen.yml
index 0b1e143703c..9a260bd97e1 100644
--- a/Resources/Prototypes/Entities/Stations/nanotrasen.yml
+++ b/Resources/Prototypes/Entities/Stations/nanotrasen.yml
@@ -27,6 +27,7 @@
- BaseStationAllEventsEligible
- BaseStationNanotrasen
- BaseStationDeliveries
+ - BaseStationGlimmer # DEN: Glimmer tracking
categories: [ HideSpawnMenu ]
components:
- type: Transform
diff --git a/Resources/Prototypes/_DEN/Stations/base.yml b/Resources/Prototypes/_DEN/Stations/base.yml
new file mode 100644
index 00000000000..5a6182ed06e
--- /dev/null
+++ b/Resources/Prototypes/_DEN/Stations/base.yml
@@ -0,0 +1,10 @@
+- type: entity
+ abstract: true
+ id: BaseStationGlimmer
+ components:
+ - type: GlimmerTracker
+ glimmerLevels: 10
+ glimmerPerLevel: 100
+ startingGlimmerLevelRange: 1, 1
+ global: true
+ offMapAffectsGlimmer: true
From f559fd4cf421e19a7ceaef3e26d4c44d37d14266 Mon Sep 17 00:00:00 2001
From: portfiend <109661617+portfiend@users.noreply.github.com>
Date: Fri, 24 Apr 2026 02:09:58 -0500
Subject: [PATCH 2/2] glimmer commands
---
.../_DEN/Glimmer/Commands/GlimmerCommand.cs | 115 ++++++++++++++++++
.../Glimmer/EntitySystems/GlimmerSystem.cs | 25 +++-
.../Components/GlimmerTrackerComponent.cs | 4 +-
Resources/Prototypes/_DEN/Stations/base.yml | 2 +-
4 files changed, 140 insertions(+), 6 deletions(-)
create mode 100644 Content.Server/_DEN/Glimmer/Commands/GlimmerCommand.cs
diff --git a/Content.Server/_DEN/Glimmer/Commands/GlimmerCommand.cs b/Content.Server/_DEN/Glimmer/Commands/GlimmerCommand.cs
new file mode 100644
index 00000000000..3d9bc143649
--- /dev/null
+++ b/Content.Server/_DEN/Glimmer/Commands/GlimmerCommand.cs
@@ -0,0 +1,115 @@
+using Content.Server._DEN.Glimmer.EntitySystems;
+using Content.Server.Administration;
+using Content.Shared._DEN.Glimmer.Components;
+using Content.Shared.Administration;
+using Content.Shared.FixedPoint;
+using Robust.Shared.Toolshed;
+
+namespace Content.Server._DEN.Glimmer.Commands;
+
+[ToolshedCommand, AdminCommand(AdminFlags.VarEdit)]
+public sealed partial class GlimmerCommand : ToolshedCommand
+{
+ private GlimmerTrackerSystem? _glimmerTracker;
+
+ [CommandImplementation("getTracker")]
+ public Entity? GetTracker([PipedArgument] EntityUid @target)
+ {
+ _glimmerTracker ??= GetSys();
+
+ if (_glimmerTracker.TryGetClosestGlimmerTracker(@target, out var tracker))
+ return tracker;
+
+ return null;
+ }
+
+ [CommandImplementation("getTracker")]
+ public Entity? GetTracker(IInvocationContext ctx)
+ {
+ _glimmerTracker ??= GetSys();
+
+ if (ctx.Session?.AttachedEntity is not { } entity)
+ return null;
+
+ if (_glimmerTracker.TryGetClosestGlimmerTracker(entity, out var tracker))
+ return tracker;
+
+ return null;
+ }
+
+ [CommandImplementation("getValue")]
+ public FixedPoint2? GetValue([PipedArgument] Entity @tracker)
+ {
+ _glimmerTracker ??= GetSys();
+ return _glimmerTracker.GetCurrentGlimmer(@tracker);
+ }
+
+ [CommandImplementation("getValue")]
+ public FixedPoint2? GetValue([PipedArgument] Entity? @tracker)
+ {
+ if (@tracker == null)
+ return FixedPoint2.Zero;
+
+ _glimmerTracker ??= GetSys();
+ return _glimmerTracker.GetCurrentGlimmer(@tracker.Value);
+ }
+
+ [CommandImplementation("getLevel")]
+ public int? GetLevel([PipedArgument] Entity @tracker)
+ {
+ _glimmerTracker ??= GetSys();
+ return _glimmerTracker.GetCurrentGlimmerLevel(@tracker);
+ }
+
+ [CommandImplementation("getLevel")]
+ public int? GetLevel([PipedArgument] Entity? @tracker)
+ {
+ if (@tracker == null)
+ return 0;
+
+ _glimmerTracker ??= GetSys();
+ return _glimmerTracker.GetCurrentGlimmerLevel(@tracker.Value);
+ }
+
+ [CommandImplementation("setValue")]
+ public Entity SetValue([PipedArgument] Entity @tracker, FixedPoint2 value)
+ {
+ _glimmerTracker ??= GetSys();
+ _glimmerTracker.SetGlimmer(@tracker, value);
+
+ return @tracker;
+ }
+
+ [CommandImplementation("setValue")]
+ public Entity? SetValue([PipedArgument] Entity? @tracker, FixedPoint2 value)
+ {
+ if (@tracker == null)
+ return @tracker;
+
+ _glimmerTracker ??= GetSys();
+ _glimmerTracker.SetGlimmer(@tracker.Value, value);
+
+ return @tracker;
+ }
+
+ [CommandImplementation("setLevel")]
+ public Entity SetLevel([PipedArgument] Entity @tracker, int level)
+ {
+ _glimmerTracker ??= GetSys();
+ _glimmerTracker.SetGlimmerLevel(@tracker, level);
+
+ return @tracker;
+ }
+
+ [CommandImplementation("setLevel")]
+ public Entity? SetLevel([PipedArgument] Entity? @tracker, int level)
+ {
+ if (@tracker == null)
+ return @tracker;
+
+ _glimmerTracker ??= GetSys();
+ _glimmerTracker.SetGlimmerLevel(@tracker.Value, level);
+
+ return @tracker;
+ }
+}
diff --git a/Content.Server/_DEN/Glimmer/EntitySystems/GlimmerSystem.cs b/Content.Server/_DEN/Glimmer/EntitySystems/GlimmerSystem.cs
index 7c6e11f13fe..84e20520968 100644
--- a/Content.Server/_DEN/Glimmer/EntitySystems/GlimmerSystem.cs
+++ b/Content.Server/_DEN/Glimmer/EntitySystems/GlimmerSystem.cs
@@ -50,7 +50,8 @@ private void OnGlimmerTrackerStartup(Entity ent, ref Co
/// The entity to retrieve the nearest valid glimmer tracker for.
/// A glimmer tracker that applies to this entity.
/// Whether or not we successfully retrieved a glimmer tracker.
- private bool TryGetClosestGlimmerTracker(EntityUid uid,
+ [PublicAPI]
+ public bool TryGetClosestGlimmerTracker(EntityUid uid,
[NotNullWhen(true)] out Entity? trackerEnt)
{
// This entity is a glimmer tracker
@@ -96,9 +97,15 @@ private bool TryGetClosestGlimmerTracker(EntityUid uid,
///
///
///
- private void SetGlimmer(Entity tracker, FixedPoint2 glimmer)
+ [PublicAPI]
+ public void SetGlimmer(Entity tracker, FixedPoint2 glimmer)
{
var comp = tracker.Comp;
+ var maxGlimmer = comp.GlimmerLevels * comp.GlimmerPerLevel;
+
+ if (glimmer < FixedPoint2.Zero || glimmer > maxGlimmer)
+ throw new ArgumentOutOfRangeException(nameof(glimmer));
+
comp.CurrentGlimmer = glimmer;
// We're adding 1 to this, so that 0 glimmer becomes level 1.
@@ -112,11 +119,23 @@ private void SetGlimmer(Entity tracker, FixedPoint2 gli
///
///
///
- private void SetGlimmerLevel(Entity tracker, int level)
+ [PublicAPI]
+ public void SetGlimmerLevel(Entity tracker, int level)
{
var comp = tracker.Comp;
+
+ if (level < 0 || level > comp.GlimmerLevels)
+ throw new ArgumentOutOfRangeException(nameof(level));
+
comp.CurrentGlimmerLevel = level;
+ // The highest glimmer level always represents the highest possible glimmer value.
+ if (level == comp.GlimmerLevels)
+ {
+ comp.CurrentGlimmer = level * comp.GlimmerPerLevel;
+ return;
+ }
+
var min = (level - 1) * comp.GlimmerPerLevel; // INCLUSIVE
var max = level * comp.GlimmerPerLevel; // EXCLUSIVE
var newGlimmer = _random.NextFloat(min.Float(), max.Float());
diff --git a/Content.Shared/_DEN/Glimmer/Components/GlimmerTrackerComponent.cs b/Content.Shared/_DEN/Glimmer/Components/GlimmerTrackerComponent.cs
index c2527f09132..6cace2b8eed 100644
--- a/Content.Shared/_DEN/Glimmer/Components/GlimmerTrackerComponent.cs
+++ b/Content.Shared/_DEN/Glimmer/Components/GlimmerTrackerComponent.cs
@@ -28,7 +28,7 @@ public sealed partial class GlimmerTrackerComponent : Component
/// What level of glimmer should we start with?
///
[DataField]
- public Vector2i StartingGlimmerLevelRange = new(1, 1);
+ public Vector2i StartingGlimmerLevelRange = new(0, 2);
///
/// An optional limit to what range of glimmer levels we can have.
@@ -81,7 +81,7 @@ public sealed partial class GlimmerTrackerComponent : Component
/// What is our current glimmer level?
///
[ViewVariables(VVAccess.ReadOnly)]
- public int CurrentGlimmerLevel = 1;
+ public int CurrentGlimmerLevel = 0;
///
/// Glimmer is represented as a range from 0 to (GlimmerLevels * GlimmerPerLevel).
diff --git a/Resources/Prototypes/_DEN/Stations/base.yml b/Resources/Prototypes/_DEN/Stations/base.yml
index 5a6182ed06e..7b04bf57ae4 100644
--- a/Resources/Prototypes/_DEN/Stations/base.yml
+++ b/Resources/Prototypes/_DEN/Stations/base.yml
@@ -5,6 +5,6 @@
- type: GlimmerTracker
glimmerLevels: 10
glimmerPerLevel: 100
- startingGlimmerLevelRange: 1, 1
+ startingGlimmerLevelRange: 0, 2
global: true
offMapAffectsGlimmer: true