From 656573805e15b9ce75c4d6d8cf0ce424f5244619 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Fri, 10 Jan 2025 15:32:10 -0500 Subject: [PATCH] Filespaced tabs --- .../Psionics/Glimmer/GlimmerReactiveSystem.cs | 590 +++++++++--------- .../Structures/GlimmerStructuresSystem.cs | 207 +++--- .../Guidebook/Psionics/Mindbreaking.xml | 2 + 3 files changed, 399 insertions(+), 400 deletions(-) diff --git a/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs b/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs index f53991db174..88849cd3f17 100644 --- a/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs +++ b/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs @@ -23,365 +23,363 @@ using Robust.Shared.Random; using Robust.Shared.Utility; -namespace Content.Server.Psionics.Glimmer +namespace Content.Server.Psionics.Glimmer; + +public sealed class GlimmerReactiveSystem : EntitySystem { - public sealed class GlimmerReactiveSystem : EntitySystem + [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; + [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!; + [Dependency] private readonly ElectrocutionSystem _electrocutionSystem = default!; + [Dependency] private readonly SharedAudioSystem _sharedAudioSystem = default!; + [Dependency] private readonly SharedAmbientSoundSystem _sharedAmbientSoundSystem = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly LightningSystem _lightning = default!; + [Dependency] private readonly ExplosionSystem _explosionSystem = default!; + [Dependency] private readonly EntityLookupSystem _entityLookupSystem = default!; + [Dependency] private readonly SharedDestructibleSystem _destructibleSystem = default!; + [Dependency] private readonly GhostSystem _ghostSystem = default!; + [Dependency] private readonly RevenantSystem _revenantSystem = default!; + [Dependency] private readonly SharedTransformSystem _transformSystem = default!; + [Dependency] private readonly SharedPointLightSystem _pointLightSystem = default!; + private ISawmill _sawmill = default!; + + public float Accumulator = 0; + public const float UpdateFrequency = 15f; + public float BeamCooldown = 3; + public GlimmerTier LastGlimmerTier = GlimmerTier.Minimal; + public bool GhostsVisible = false; + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(Reset); + + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnComponentRemove); + SubscribeLocalEvent(OnPowerChanged); + SubscribeLocalEvent(OnTierChanged); + SubscribeLocalEvent>(AddShockVerb); + SubscribeLocalEvent(OnDamageChanged); + SubscribeLocalEvent(OnDestroyed); + SubscribeLocalEvent(OnUnanchorAttempt); + SubscribeLocalEvent(OnMeleeThrowOnHitAttempt); + } + + /// + /// Update relevant state on an Entity. + /// + /// The number of steps in tier + /// difference since last update. This can be zero for the sake of + /// toggling the enabled states. + private void UpdateEntityState(EntityUid uid, SharedGlimmerReactiveComponent component, GlimmerTier currentGlimmerTier, int glimmerTierDelta) { - [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; - [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!; - [Dependency] private readonly ElectrocutionSystem _electrocutionSystem = default!; - [Dependency] private readonly SharedAudioSystem _sharedAudioSystem = default!; - [Dependency] private readonly SharedAmbientSoundSystem _sharedAmbientSoundSystem = default!; - [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly LightningSystem _lightning = default!; - [Dependency] private readonly ExplosionSystem _explosionSystem = default!; - [Dependency] private readonly EntityLookupSystem _entityLookupSystem = default!; - [Dependency] private readonly SharedDestructibleSystem _destructibleSystem = default!; - [Dependency] private readonly GhostSystem _ghostSystem = default!; - [Dependency] private readonly RevenantSystem _revenantSystem = default!; - [Dependency] private readonly SharedTransformSystem _transformSystem = default!; - [Dependency] private readonly SharedPointLightSystem _pointLightSystem = default!; - private ISawmill _sawmill = default!; - - public float Accumulator = 0; - public const float UpdateFrequency = 15f; - public float BeamCooldown = 3; - public GlimmerTier LastGlimmerTier = GlimmerTier.Minimal; - public bool GhostsVisible = false; - public override void Initialize() + var isEnabled = true; + + if (component.RequiresApcPower + && TryComp(uid, out ApcPowerReceiverComponent? apcPower)) + isEnabled = apcPower.Powered; + + _appearanceSystem.SetData(uid, GlimmerReactiveVisuals.GlimmerTier, isEnabled ? currentGlimmerTier : GlimmerTier.Minimal); + + // Update ambient sound + if (TryComp(uid, out GlimmerSoundComponent? glimmerSound) + && TryComp(uid, out AmbientSoundComponent? ambientSoundComponent) + && glimmerSound.GetSound(currentGlimmerTier, out SoundSpecifier? spec) + && spec != null) + _sharedAmbientSoundSystem.SetSound(uid, spec, ambientSoundComponent); + + // Update point light + if (component.ModulatesPointLight + && _pointLightSystem.TryGetLight(uid, out var pointLight)) { - base.Initialize(); - SubscribeLocalEvent(Reset); - - SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnComponentRemove); - SubscribeLocalEvent(OnPowerChanged); - SubscribeLocalEvent(OnTierChanged); - SubscribeLocalEvent>(AddShockVerb); - SubscribeLocalEvent(OnDamageChanged); - SubscribeLocalEvent(OnDestroyed); - SubscribeLocalEvent(OnUnanchorAttempt); - SubscribeLocalEvent(OnMeleeThrowOnHitAttempt); + _pointLightSystem.SetEnabled(uid, isEnabled ? currentGlimmerTier != GlimmerTier.Minimal : false, pointLight); + _pointLightSystem.SetEnergy(uid, pointLight.Energy + glimmerTierDelta * component.GlimmerToLightEnergyFactor, pointLight); + _pointLightSystem.SetRadius(uid, pointLight.Radius + glimmerTierDelta * component.GlimmerToLightRadiusFactor, pointLight); } - /// - /// Update relevant state on an Entity. - /// - /// The number of steps in tier - /// difference since last update. This can be zero for the sake of - /// toggling the enabled states. - private void UpdateEntityState(EntityUid uid, SharedGlimmerReactiveComponent component, GlimmerTier currentGlimmerTier, int glimmerTierDelta) - { - var isEnabled = true; + } - if (component.RequiresApcPower - && TryComp(uid, out ApcPowerReceiverComponent? apcPower)) - isEnabled = apcPower.Powered; + /// + /// Track when the component comes online so it can be given the + /// current status of the glimmer tier, if it wasn't around when an + /// update went out. + /// + private void OnMapInit(EntityUid uid, SharedGlimmerReactiveComponent component, MapInitEvent args) + { + if (component.RequiresApcPower && !HasComp(uid)) + _sawmill.Warning($"{ToPrettyString(uid)} had RequiresApcPower set to true but no ApcPowerReceiverComponent was found on init."); - _appearanceSystem.SetData(uid, GlimmerReactiveVisuals.GlimmerTier, isEnabled ? currentGlimmerTier : GlimmerTier.Minimal); + UpdateEntityState(uid, component, LastGlimmerTier, (int) LastGlimmerTier); + } - // Update ambient sound - if (TryComp(uid, out GlimmerSoundComponent? glimmerSound) - && TryComp(uid, out AmbientSoundComponent? ambientSoundComponent) - && glimmerSound.GetSound(currentGlimmerTier, out SoundSpecifier? spec) - && spec != null) - _sharedAmbientSoundSystem.SetSound(uid, spec, ambientSoundComponent); + /// + /// Reset the glimmer tier appearance data if the component's removed, + /// just in case some objects can temporarily become reactive to the + /// glimmer. + /// + private void OnComponentRemove(EntityUid uid, SharedGlimmerReactiveComponent component, ComponentRemove args) + { + UpdateEntityState(uid, component, GlimmerTier.Minimal, -1 * (int) LastGlimmerTier); + } - // Update point light - if (component.ModulatesPointLight - && _pointLightSystem.TryGetLight(uid, out var pointLight)) - { - _pointLightSystem.SetEnabled(uid, isEnabled ? currentGlimmerTier != GlimmerTier.Minimal : false, pointLight); - _pointLightSystem.SetEnergy(uid, pointLight.Energy + glimmerTierDelta * component.GlimmerToLightEnergyFactor, pointLight); - _pointLightSystem.SetRadius(uid, pointLight.Radius + glimmerTierDelta * component.GlimmerToLightRadiusFactor, pointLight); - } + /// + /// If the Entity has RequiresApcPower set to true, this will force an + /// update to the entity's state. + /// + private void OnPowerChanged(EntityUid uid, SharedGlimmerReactiveComponent component, ref PowerChangedEvent args) + { + if (component.RequiresApcPower) + UpdateEntityState(uid, component, LastGlimmerTier, 0); + } - } + /// + /// Enable / disable special effects from higher tiers. + /// + private void OnTierChanged(EntityUid uid, SharedGlimmerReactiveComponent component, GlimmerTierChangedEvent args) + { + if (!TryComp(uid, out var receiver)) + return; - /// - /// Track when the component comes online so it can be given the - /// current status of the glimmer tier, if it wasn't around when an - /// update went out. - /// - private void OnMapInit(EntityUid uid, SharedGlimmerReactiveComponent component, MapInitEvent args) + if (args.CurrentTier >= GlimmerTier.Dangerous) { - if (component.RequiresApcPower && !HasComp(uid)) - _sawmill.Warning($"{ToPrettyString(uid)} had RequiresApcPower set to true but no ApcPowerReceiverComponent was found on init."); + if (!Transform(uid).Anchored) + AnchorOrExplode(uid); - UpdateEntityState(uid, component, LastGlimmerTier, (int) LastGlimmerTier); + receiver.PowerDisabled = false; + receiver.NeedsPower = false; } - - /// - /// Reset the glimmer tier appearance data if the component's removed, - /// just in case some objects can temporarily become reactive to the - /// glimmer. - /// - private void OnComponentRemove(EntityUid uid, SharedGlimmerReactiveComponent component, ComponentRemove args) + else { - UpdateEntityState(uid, component, GlimmerTier.Minimal, -1 * (int) LastGlimmerTier); + receiver.NeedsPower = true; } + } - /// - /// If the Entity has RequiresApcPower set to true, this will force an - /// update to the entity's state. - /// - private void OnPowerChanged(EntityUid uid, SharedGlimmerReactiveComponent component, ref PowerChangedEvent args) - { - if (component.RequiresApcPower) - UpdateEntityState(uid, component, LastGlimmerTier, 0); - } + private void AddShockVerb(EntityUid uid, SharedGlimmerReactiveComponent component, GetVerbsEvent args) + { + if (!args.CanAccess + || !args.CanInteract + || !TryComp(uid, out var receiver) + || receiver.NeedsPower) + return; - /// - /// Enable / disable special effects from higher tiers. - /// - private void OnTierChanged(EntityUid uid, SharedGlimmerReactiveComponent component, GlimmerTierChangedEvent args) + AlternativeVerb verb = new() { - if (!TryComp(uid, out var receiver)) - return; - - if (args.CurrentTier >= GlimmerTier.Dangerous) + Act = () => { - if (!Transform(uid).Anchored) - AnchorOrExplode(uid); + _sharedAudioSystem.PlayPvs(component.ShockNoises, args.User); + _electrocutionSystem.TryDoElectrocution(args.User, null, (int) _glimmerSystem.GlimmerOutput / 200, TimeSpan.FromSeconds(_glimmerSystem.GlimmerOutput / 100), false); + }, + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/Spare/poweronoff.svg.192dpi.png")), + Text = Loc.GetString("power-switch-component-toggle-verb"), + Priority = -3 + }; + args.Verbs.Add(verb); + } - receiver.PowerDisabled = false; - receiver.NeedsPower = false; - } - else - { - receiver.NeedsPower = true; - } - } + private void OnDamageChanged(EntityUid uid, SharedGlimmerReactiveComponent component, DamageChangedEvent args) + { + if (args.Origin == null + || !_random.Prob(_glimmerSystem.GetGlimmerEquilibriumRatio() / 10)) + return; + + var tier = _glimmerSystem.GetGlimmerTier(); + if (tier < GlimmerTier.High) + return; + Beam(uid, args.Origin.Value, tier); + } - private void AddShockVerb(EntityUid uid, SharedGlimmerReactiveComponent component, GetVerbsEvent args) - { - if (!args.CanAccess - || !args.CanInteract - || !TryComp(uid, out var receiver) - || receiver.NeedsPower) - return; + private void OnDestroyed(EntityUid uid, SharedGlimmerReactiveComponent component, DestructionEventArgs args) + { + Spawn("MaterialBluespace1", Transform(uid).Coordinates); - AlternativeVerb verb = new() - { - Act = () => - { - _sharedAudioSystem.PlayPvs(component.ShockNoises, args.User); - _electrocutionSystem.TryDoElectrocution(args.User, null, (int) _glimmerSystem.GlimmerOutput / 200, TimeSpan.FromSeconds(_glimmerSystem.GlimmerOutput / 100), false); - }, - Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/Spare/poweronoff.svg.192dpi.png")), - Text = Loc.GetString("power-switch-component-toggle-verb"), - Priority = -3 - }; - args.Verbs.Add(verb); - } + var tier = _glimmerSystem.GetGlimmerTier(); + if (tier < GlimmerTier.High) + return; - private void OnDamageChanged(EntityUid uid, SharedGlimmerReactiveComponent component, DamageChangedEvent args) - { - if (args.Origin == null - || !_random.Prob(_glimmerSystem.GetGlimmerEquilibriumRatio() / 10)) - return; + var totalIntensity = _glimmerSystem.GlimmerOutput * 2; + var slope = 11 - _glimmerSystem.GlimmerOutput / 100; + var maxIntensity = 20; - var tier = _glimmerSystem.GetGlimmerTier(); - if (tier < GlimmerTier.High) - return; - Beam(uid, args.Origin.Value, tier); - } + var removed = _glimmerSystem.GlimmerOutput * _random.NextFloat(0.1f, 0.15f); + _glimmerSystem.DeltaGlimmerInput(-removed); + BeamRandomNearProber(uid, (int) _glimmerSystem.GlimmerOutput / 350, _glimmerSystem.GlimmerOutput / 50); + _explosionSystem.QueueExplosion(uid, "Default", totalIntensity, slope, maxIntensity); + } - private void OnDestroyed(EntityUid uid, SharedGlimmerReactiveComponent component, DestructionEventArgs args) - { - Spawn("MaterialBluespace1", Transform(uid).Coordinates); + private void OnUnanchorAttempt(EntityUid uid, SharedGlimmerReactiveComponent component, UnanchorAttemptEvent args) + { + if (_glimmerSystem.GetGlimmerTier() < GlimmerTier.Dangerous) + return; - var tier = _glimmerSystem.GetGlimmerTier(); - if (tier < GlimmerTier.High) - return; + _sharedAudioSystem.PlayPvs(component.ShockNoises, args.User); + _electrocutionSystem.TryDoElectrocution(args.User, null, (int) _glimmerSystem.GlimmerOutput / 200, TimeSpan.FromSeconds(_glimmerSystem.GlimmerOutput / 100), false); + args.Cancel(); + } - var totalIntensity = _glimmerSystem.GlimmerOutput * 2; - var slope = 11 - _glimmerSystem.GlimmerOutput / 100; - var maxIntensity = 20; + public void BeamRandomNearProber(EntityUid prober, int targets, float range = 10f) + { + List targetList = new(); + foreach (var (target, status) in _entityLookupSystem.GetEntitiesInRange(_transformSystem.GetMapCoordinates(prober), range)) + if (status.AllowedEffects.Contains("Electrocution")) + targetList.Add(target); - var removed = _glimmerSystem.GlimmerOutput * _random.NextFloat(0.1f, 0.15f); - _glimmerSystem.DeltaGlimmerInput(-removed); - BeamRandomNearProber(uid, (int) _glimmerSystem.GlimmerOutput / 350, _glimmerSystem.GlimmerOutput / 50); - _explosionSystem.QueueExplosion(uid, "Default", totalIntensity, slope, maxIntensity); - } + foreach (var reactive in _entityLookupSystem.GetEntitiesInRange(_transformSystem.GetMapCoordinates(prober), range)) + targetList.Add(reactive); - private void OnUnanchorAttempt(EntityUid uid, SharedGlimmerReactiveComponent component, UnanchorAttemptEvent args) + _random.Shuffle(targetList); + foreach (var target in targetList) { - if (_glimmerSystem.GetGlimmerTier() < GlimmerTier.Dangerous) + if (targets <= 0) return; - _sharedAudioSystem.PlayPvs(component.ShockNoises, args.User); - _electrocutionSystem.TryDoElectrocution(args.User, null, (int) _glimmerSystem.GlimmerOutput / 200, TimeSpan.FromSeconds(_glimmerSystem.GlimmerOutput / 100), false); - args.Cancel(); + Beam(prober, target, _glimmerSystem.GetGlimmerTier(), false); + targets--; } + } - public void BeamRandomNearProber(EntityUid prober, int targets, float range = 10f) - { - List targetList = new(); - foreach (var (target, status) in _entityLookupSystem.GetEntitiesInRange(_transformSystem.GetMapCoordinates(prober), range)) - if (status.AllowedEffects.Contains("Electrocution")) - targetList.Add(target); + private void Beam(EntityUid prober, EntityUid target, GlimmerTier tier, bool obeyCD = true) + { + if (obeyCD && BeamCooldown != 0 + || Deleted(prober) + || Deleted(target)) + return; - foreach (var reactive in _entityLookupSystem.GetEntitiesInRange(_transformSystem.GetMapCoordinates(prober), range)) - targetList.Add(reactive); + var lxform = Transform(prober); + var txform = Transform(target); - _random.Shuffle(targetList); - foreach (var target in targetList) - { - if (targets <= 0) - return; + if (!lxform.Coordinates.TryDistance(EntityManager, txform.Coordinates, out var distance)) + return; + if (distance > _glimmerSystem.GlimmerOutput / 100) + return; - Beam(prober, target, _glimmerSystem.GetGlimmerTier(), false); - targets--; - } - } + string beamproto; - private void Beam(EntityUid prober, EntityUid target, GlimmerTier tier, bool obeyCD = true) + switch (tier) { - if (obeyCD && BeamCooldown != 0 - || Deleted(prober) - || Deleted(target)) - return; - - var lxform = Transform(prober); - var txform = Transform(target); - - if (!lxform.Coordinates.TryDistance(EntityManager, txform.Coordinates, out var distance)) - return; - if (distance > _glimmerSystem.GlimmerOutput / 100) - return; - - string beamproto; - - switch (tier) - { - case GlimmerTier.Dangerous: - beamproto = "SuperchargedLightning"; - break; - case GlimmerTier.Critical: - beamproto = "HyperchargedLightning"; - break; - default: - beamproto = "ChargedLightning"; - break; - } + case GlimmerTier.Dangerous: + beamproto = "SuperchargedLightning"; + break; + case GlimmerTier.Critical: + beamproto = "HyperchargedLightning"; + break; + default: + beamproto = "ChargedLightning"; + break; + } - _lightning.ShootLightning(prober, target, beamproto); - BeamCooldown += 3f; - } + _lightning.ShootLightning(prober, target, beamproto); + BeamCooldown += 3f; + } - private void AnchorOrExplode(EntityUid uid) - { - if (Transform(uid).GridUid is null) - _destructibleSystem.DestroyEntity(uid); + private void AnchorOrExplode(EntityUid uid) + { + if (Transform(uid).GridUid is null) + _destructibleSystem.DestroyEntity(uid); - if (HasComp(uid)) - _transformSystem.AnchorEntity(uid, Transform(uid)); - } + if (HasComp(uid)) + _transformSystem.AnchorEntity(uid, Transform(uid)); + } - private void OnMeleeThrowOnHitAttempt(Entity ent, ref AttemptMeleeThrowOnHitEvent args) - { - if (_glimmerSystem.GetGlimmerTier() < GlimmerTier.Dangerous) - return; + private void OnMeleeThrowOnHitAttempt(Entity ent, ref AttemptMeleeThrowOnHitEvent args) + { + if (_glimmerSystem.GetGlimmerTier() < GlimmerTier.Dangerous) + return; - args.Cancelled = true; - args.Handled = true; + args.Cancelled = true; + args.Handled = true; - _lightning.ShootRandomLightnings(ent, 10, 2, "SuperchargedLightning", 2, false); + _lightning.ShootRandomLightnings(ent, 10, 2, "SuperchargedLightning", 2, false); - // Check if the parent of the user is alive, which will be the case if the user is an item and is being held. - var zapTarget = _transformSystem.GetParentUid(args.User); - if (TryComp(zapTarget, out _)) - _electrocutionSystem.TryDoElectrocution(zapTarget, ent, 5, TimeSpan.FromSeconds(3), true, - ignoreInsulation: true); - } + // Check if the parent of the user is alive, which will be the case if the user is an item and is being held. + var zapTarget = _transformSystem.GetParentUid(args.User); + if (TryComp(zapTarget, out _)) + _electrocutionSystem.TryDoElectrocution(zapTarget, ent, 5, TimeSpan.FromSeconds(3), true, + ignoreInsulation: true); + } - private void Reset(RoundRestartCleanupEvent args) - { - Accumulator = 0; + private void Reset(RoundRestartCleanupEvent args) + { + Accumulator = 0; + + // It is necessary that the GlimmerTier is reset to the default + // tier on round restart. This system will persist through + // restarts, and an undesired event will fire as a result after the + // start of the new round, causing modulatable PointLights to have + // negative Energy if the tier was higher than Minimal on restart. + LastGlimmerTier = GlimmerTier.Minimal; + } - // It is necessary that the GlimmerTier is reset to the default - // tier on round restart. This system will persist through - // restarts, and an undesired event will fire as a result after the - // start of the new round, causing modulatable PointLights to have - // negative Energy if the tier was higher than Minimal on restart. - LastGlimmerTier = GlimmerTier.Minimal; - } + public override void Update(float frameTime) + { + base.Update(frameTime); + Accumulator += frameTime; + BeamCooldown = Math.Max(0, BeamCooldown - frameTime); - public override void Update(float frameTime) + if (Accumulator > UpdateFrequency) { - base.Update(frameTime); - Accumulator += frameTime; - BeamCooldown = Math.Max(0, BeamCooldown - frameTime); + var currentGlimmerTier = _glimmerSystem.GetGlimmerTier(); - if (Accumulator > UpdateFrequency) + var reactives = EntityQuery(); + if (currentGlimmerTier != LastGlimmerTier) { - var currentGlimmerTier = _glimmerSystem.GetGlimmerTier(); + var glimmerTierDelta = (int) currentGlimmerTier - (int) LastGlimmerTier; + var ev = new GlimmerTierChangedEvent(LastGlimmerTier, currentGlimmerTier, glimmerTierDelta); - var reactives = EntityQuery(); - if (currentGlimmerTier != LastGlimmerTier) + foreach (var reactive in reactives) { - var glimmerTierDelta = (int) currentGlimmerTier - (int) LastGlimmerTier; - var ev = new GlimmerTierChangedEvent(LastGlimmerTier, currentGlimmerTier, glimmerTierDelta); - - foreach (var reactive in reactives) - { - UpdateEntityState(reactive.Owner, reactive, currentGlimmerTier, glimmerTierDelta); - RaiseLocalEvent(reactive.Owner, ev); - } - - LastGlimmerTier = currentGlimmerTier; + UpdateEntityState(reactive.Owner, reactive, currentGlimmerTier, glimmerTierDelta); + RaiseLocalEvent(reactive.Owner, ev); } - if (currentGlimmerTier == GlimmerTier.Critical) - { - _ghostSystem.MakeVisible(true); - _revenantSystem.MakeVisible(true); - GhostsVisible = true; - foreach (var reactive in reactives) - BeamRandomNearProber(reactive.Owner, 1, 12); - } - else if (GhostsVisible == true) - { - _ghostSystem.MakeVisible(false); - _revenantSystem.MakeVisible(false); - GhostsVisible = false; - } - Accumulator = 0; + + LastGlimmerTier = currentGlimmerTier; } + if (currentGlimmerTier == GlimmerTier.Critical) + { + _ghostSystem.MakeVisible(true); + _revenantSystem.MakeVisible(true); + GhostsVisible = true; + foreach (var reactive in reactives) + BeamRandomNearProber(reactive.Owner, 1, 12); + } + else if (GhostsVisible == true) + { + _ghostSystem.MakeVisible(false); + _revenantSystem.MakeVisible(false); + GhostsVisible = false; + } + Accumulator = 0; } } +} + +/// +/// This event is fired when the broader glimmer tier has changed, +/// not on every single adjustment to the glimmer count. +/// +/// has the exact +/// values corresponding to tiers. +/// +public class GlimmerTierChangedEvent : EntityEventArgs +{ + /// + /// What was the last glimmer tier before this event fired? + /// + public readonly GlimmerTier LastTier; /// - /// This event is fired when the broader glimmer tier has changed, - /// not on every single adjustment to the glimmer count. - /// - /// has the exact - /// values corresponding to tiers. + /// What is the current glimmer tier? /// - public class GlimmerTierChangedEvent : EntityEventArgs + public readonly GlimmerTier CurrentTier; + + /// + /// What is the change in tiers between the last and current tier? + /// + public readonly int TierDelta; + + public GlimmerTierChangedEvent(GlimmerTier lastTier, GlimmerTier currentTier, int tierDelta) { - /// - /// What was the last glimmer tier before this event fired? - /// - public readonly GlimmerTier LastTier; - - /// - /// What is the current glimmer tier? - /// - public readonly GlimmerTier CurrentTier; - - /// - /// What is the change in tiers between the last and current tier? - /// - public readonly int TierDelta; - - public GlimmerTierChangedEvent(GlimmerTier lastTier, GlimmerTier currentTier, int tierDelta) - { - LastTier = lastTier; - CurrentTier = currentTier; - TierDelta = tierDelta; - } + LastTier = lastTier; + CurrentTier = currentTier; + TierDelta = tierDelta; } } - diff --git a/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs b/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs index 9be8aa8ca55..67652c5a7d5 100644 --- a/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs +++ b/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs @@ -6,128 +6,127 @@ using Content.Shared.Psionics.Glimmer; using Content.Shared.Power; -namespace Content.Server.Psionics.Glimmer +namespace Content.Server.Psionics.Glimmer; + +/// +/// Handles structures which add/subtract glimmer. +/// +public sealed class GlimmerStructuresSystem : EntitySystem { - /// - /// Handles structures which add/subtract glimmer. - /// - public sealed class GlimmerStructuresSystem : EntitySystem - { - [Dependency] private readonly PowerReceiverSystem _powerReceiverSystem = default!; - [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; + [Dependency] private readonly PowerReceiverSystem _powerReceiverSystem = default!; + [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; - public override void Initialize() - { - base.Initialize(); + public override void Initialize() + { + base.Initialize(); - SubscribeLocalEvent(OnAnomalyVesselPowerChanged); + SubscribeLocalEvent(OnAnomalyVesselPowerChanged); - SubscribeLocalEvent(OnAnomalyPulse); - SubscribeLocalEvent(OnAnomalySupercritical); - SubscribeLocalEvent(OnMobStateChanged); - SubscribeLocalEvent(OnInit); - } + SubscribeLocalEvent(OnAnomalyPulse); + SubscribeLocalEvent(OnAnomalySupercritical); + SubscribeLocalEvent(OnMobStateChanged); + SubscribeLocalEvent(OnInit); + } - private void OnInit(EntityUid uid, GlimmerSourceComponent component, ComponentStartup args) + private void OnInit(EntityUid uid, GlimmerSourceComponent component, ComponentStartup args) + { + if (component.ResearchPointGeneration != null) { - if (component.ResearchPointGeneration != null) - { - EnsureComp(uid, out var points); - points.PointsPerSecond = component.ResearchPointGeneration.Value; - points.Active = true; - } + 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 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 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 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; - } + private void OnMobStateChanged(EntityUid uid, GlimmerSourceComponent component, ref MobStateChangedEvent args) + { + if (args.NewMobState != MobState.Alive) + component.Active = false; + } - public override void Update(float frameTime) + public override void Update(float frameTime) + { + base.Update(frameTime); + var glimmerSources = Count(); + foreach (var source in EntityQuery()) { - base.Update(frameTime); - var glimmerSources = Count(); - foreach (var source in EntityQuery()) + if (!_powerReceiverSystem.IsPowered(source.Owner) + && source.RequiresPower) { - if (!_powerReceiverSystem.IsPowered(source.Owner) - && source.RequiresPower) - { - glimmerSources--; - continue; - } + glimmerSources--; + continue; + } - if (!source.Active) - { - glimmerSources--; - continue; - } + if (!source.Active) + { + glimmerSources--; + continue; + } - source.Accumulator += frameTime; + source.Accumulator += frameTime; - if (source.Accumulator > source.SecondsPerGlimmer) + 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 { - 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)); - } + _glimmerSystem.DeltaGlimmerInput(-(_glimmerSystem.GlimmerOutput > glimmerEquilibrium + ? MathF.Pow(_glimmerSystem.GetGlimmerOutputInteger() - source.GlimmerExponentOffset + glimmerSources, 2) : 1f) + * (_glimmerSystem.GlimmerOutput > glimmerEquilibrium ? _glimmerSystem.GetGlimmerEquilibriumRatio() : 1f)); } } } diff --git a/Resources/ServerInfo/Guidebook/Psionics/Mindbreaking.xml b/Resources/ServerInfo/Guidebook/Psionics/Mindbreaking.xml index 546c95d5b1a..b897d1cccf0 100644 --- a/Resources/ServerInfo/Guidebook/Psionics/Mindbreaking.xml +++ b/Resources/ServerInfo/Guidebook/Psionics/Mindbreaking.xml @@ -12,4 +12,6 @@ spark of humanity, making it so that for the rest of their natural life, they ca Mind Breaking is performed by either imbibing a pill of Mindbreaker Toxin, or an injection of Soulbreaker. It is to be performed only as an emergency measure during a Code White situation, and only with the permission of the station's Commanding Officer. Mind Breaking may also be given by the station's Commanding Officer as a Capital level punishment for the most egregious crimes, such as using psychic powers to commit heinous acts. + +[color=#ff0000]MINDBREAKING IS IRREVERSIBLE, AND CAN RENDER ITS VICTIM A NON-SENTIENT HUSK. DO NOT PERFORM THIS PROCEDURE WITHOUT A GOOD REASON.[/color]