From 0c46f9900432a972a288f31bd557b310f3c4fbe2 Mon Sep 17 00:00:00 2001 From: Moony Date: Thu, 29 Sep 2022 18:23:12 -0500 Subject: [PATCH] Blindness, Narcolepsy, Pacifism, and uncontrollable sneezing (#11489) * start work * blindness actually works now * doc * doc you too. * i desire to sneeze my lungs out * no punchie * s Co-authored-by: moonheart08 --- .../Traits/Assorted/NarcolepsyComponent.cs | 22 ++++++++ .../Traits/Assorted/NarcolepsySystem.cs | 53 +++++++++++++++++++ .../Traits/Assorted/PacifistComponent.cs | 10 ++++ .../Traits/Assorted/PacifistSystem.cs | 17 ++++++ .../Assorted/UncontrollableSnoughComponent.cs | 28 ++++++++++ .../Assorted/UncontrollableSnoughSystem.cs | 52 ++++++++++++++++++ .../Eye/Blinding/SharedBlindingSystem.cs | 2 + .../Assorted/PermanentBlindnessComponent.cs | 12 +++++ .../Assorted/PermanentBlindnessSystem.cs | 41 ++++++++++++++ Resources/Locale/en-US/traits/traits.ftl | 1 + Resources/Prototypes/Traits/disabilities.yml | 19 +++++++ .../Prototypes/Traits/inconveniences.yml | 10 ++++ 12 files changed, 267 insertions(+) create mode 100644 Content.Server/Traits/Assorted/NarcolepsyComponent.cs create mode 100644 Content.Server/Traits/Assorted/NarcolepsySystem.cs create mode 100644 Content.Server/Traits/Assorted/PacifistComponent.cs create mode 100644 Content.Server/Traits/Assorted/PacifistSystem.cs create mode 100644 Content.Server/Traits/Assorted/UncontrollableSnoughComponent.cs create mode 100644 Content.Server/Traits/Assorted/UncontrollableSnoughSystem.cs create mode 100644 Content.Shared/Traits/Assorted/PermanentBlindnessComponent.cs create mode 100644 Content.Shared/Traits/Assorted/PermanentBlindnessSystem.cs create mode 100644 Resources/Locale/en-US/traits/traits.ftl create mode 100644 Resources/Prototypes/Traits/disabilities.yml create mode 100644 Resources/Prototypes/Traits/inconveniences.yml diff --git a/Content.Server/Traits/Assorted/NarcolepsyComponent.cs b/Content.Server/Traits/Assorted/NarcolepsyComponent.cs new file mode 100644 index 0000000000..6cf153fd51 --- /dev/null +++ b/Content.Server/Traits/Assorted/NarcolepsyComponent.cs @@ -0,0 +1,22 @@ +namespace Content.Server.Traits.Assorted; + +/// +/// This is used for the narcolepsy trait. +/// +[RegisterComponent, Access(typeof(NarcolepsySystem))] +public sealed class NarcolepsyComponent : Component +{ + /// + /// The random time between incidents, (min, max). + /// + [DataField("timeBetweenIncidents", required: true)] + public Vector2 TimeBetweenIncidents { get; } + + /// + /// The duration of incidents, (min, max). + /// + [DataField("durationOfIncident", required: true)] + public Vector2 DurationOfIncident { get; } + + public float NextIncidentTime; +} diff --git a/Content.Server/Traits/Assorted/NarcolepsySystem.cs b/Content.Server/Traits/Assorted/NarcolepsySystem.cs new file mode 100644 index 0000000000..0d4bb90710 --- /dev/null +++ b/Content.Server/Traits/Assorted/NarcolepsySystem.cs @@ -0,0 +1,53 @@ +using Content.Shared.Bed.Sleep; +using Content.Shared.StatusEffect; +using Robust.Shared.Random; + +namespace Content.Server.Traits.Assorted; + +/// +/// This handles narcolepsy, causing the affected to fall asleep uncontrollably at a random interval. +/// +public sealed class NarcolepsySystem : EntitySystem +{ + private const string StatusEffectKey = "ForcedSleep"; // Same one used by N2O and other sleep chems. + + [Dependency] private readonly StatusEffectsSystem _statusEffects = default!; + [Dependency] private readonly IRobustRandom _random = default!; + + /// + public override void Initialize() + { + SubscribeLocalEvent(SetupNarcolepsy); + } + + private void SetupNarcolepsy(EntityUid uid, NarcolepsyComponent component, ComponentStartup args) + { + component.NextIncidentTime = + _random.NextFloat(component.TimeBetweenIncidents.X, component.TimeBetweenIncidents.Y); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + foreach (var narcolepsy in EntityQuery()) + { + narcolepsy.NextIncidentTime -= frameTime; + + if (narcolepsy.NextIncidentTime >= 0) + continue; + + // Set the new time. + narcolepsy.NextIncidentTime += + _random.NextFloat(narcolepsy.TimeBetweenIncidents.X, narcolepsy.TimeBetweenIncidents.Y); + + var duration = _random.NextFloat(narcolepsy.DurationOfIncident.X, narcolepsy.DurationOfIncident.Y); + + // Make sure the sleep time doesn't cut into the time to next incident. + narcolepsy.NextIncidentTime += duration; + + _statusEffects.TryAddStatusEffect(narcolepsy.Owner, StatusEffectKey, + TimeSpan.FromSeconds(duration), false); + } + } +} diff --git a/Content.Server/Traits/Assorted/PacifistComponent.cs b/Content.Server/Traits/Assorted/PacifistComponent.cs new file mode 100644 index 0000000000..095dc651fc --- /dev/null +++ b/Content.Server/Traits/Assorted/PacifistComponent.cs @@ -0,0 +1,10 @@ +namespace Content.Server.Traits.Assorted; + +/// +/// This is used for enforcing pacifism. +/// +[RegisterComponent] +public sealed class PacifistComponent : Component +{ + +} diff --git a/Content.Server/Traits/Assorted/PacifistSystem.cs b/Content.Server/Traits/Assorted/PacifistSystem.cs new file mode 100644 index 0000000000..5d8b1f44db --- /dev/null +++ b/Content.Server/Traits/Assorted/PacifistSystem.cs @@ -0,0 +1,17 @@ +using Content.Shared.CombatMode.Pacification; + +namespace Content.Server.Traits.Assorted; + +/// +/// This handles enforced pacifism. +/// +public sealed class PacifistSystem : EntitySystem +{ + public override void Update(float frameTime) + { + foreach (var comp in EntityQuery()) + { + EnsureComp(comp.Owner); // It's a status effect so just enforce it. + } + } +} diff --git a/Content.Server/Traits/Assorted/UncontrollableSnoughComponent.cs b/Content.Server/Traits/Assorted/UncontrollableSnoughComponent.cs new file mode 100644 index 0000000000..bd36c6fa25 --- /dev/null +++ b/Content.Server/Traits/Assorted/UncontrollableSnoughComponent.cs @@ -0,0 +1,28 @@ +using Robust.Shared.Audio; + +namespace Content.Server.Traits.Assorted; + +/// +/// This is used for the occasional sneeze or cough. +/// +[RegisterComponent] +public sealed class UncontrollableSnoughComponent : Component +{ + /// + /// Message to play when snoughing. + /// + [DataField("snoughMessage")] public string SnoughMessage = "disease-sneeze"; + + /// + /// Sound to play when snoughing. + /// + [DataField("snoughSound")] public SoundSpecifier? SnoughSound; + + /// + /// The random time between incidents, (min, max). + /// + [DataField("timeBetweenIncidents", required: true)] + public Vector2 TimeBetweenIncidents { get; } + + public float NextIncidentTime; +} diff --git a/Content.Server/Traits/Assorted/UncontrollableSnoughSystem.cs b/Content.Server/Traits/Assorted/UncontrollableSnoughSystem.cs new file mode 100644 index 0000000000..266dc5a8cc --- /dev/null +++ b/Content.Server/Traits/Assorted/UncontrollableSnoughSystem.cs @@ -0,0 +1,52 @@ +using Content.Server.Disease; +using Content.Shared.Audio; +using Robust.Server.GameObjects; +using Robust.Shared.Audio; +using Robust.Shared.Player; +using Robust.Shared.Random; + +namespace Content.Server.Traits.Assorted; + +/// +/// This handles making people randomly cough/sneeze without a disease. +/// +public sealed class UncontrollableSnoughSystem : EntitySystem +{ + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly DiseaseSystem _diseaseSystem = default!; + [Dependency] private readonly AudioSystem _audioSystem = default!; + + /// + public override void Initialize() + { + SubscribeLocalEvent(SetupSnough); + } + + private void SetupSnough(EntityUid uid, UncontrollableSnoughComponent component, ComponentStartup args) + { + component.NextIncidentTime = + _random.NextFloat(component.TimeBetweenIncidents.X, component.TimeBetweenIncidents.Y); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + foreach (var snough in EntityQuery()) + { + snough.NextIncidentTime -= frameTime; + + if (snough.NextIncidentTime >= 0) + continue; + + // Set the new time. + snough.NextIncidentTime += + _random.NextFloat(snough.TimeBetweenIncidents.X, snough.TimeBetweenIncidents.Y); + + if (snough.SnoughSound != null) + _audioSystem.PlayPvs(snough.SnoughSound, snough.Owner); + + _diseaseSystem.SneezeCough(snough.Owner, null, snough.SnoughMessage, false); + } + } +} diff --git a/Content.Shared/Eye/Blinding/SharedBlindingSystem.cs b/Content.Shared/Eye/Blinding/SharedBlindingSystem.cs index 3699df88bb..094d99f910 100644 --- a/Content.Shared/Eye/Blinding/SharedBlindingSystem.cs +++ b/Content.Shared/Eye/Blinding/SharedBlindingSystem.cs @@ -104,6 +104,8 @@ namespace Content.Shared.Eye.Blinding } blindable.Sources = Math.Max(blindable.Sources, 0); + + Dirty(blindable); } public void AdjustEyeDamage(EntityUid uid, bool add, BlindableComponent? blindable = null) diff --git a/Content.Shared/Traits/Assorted/PermanentBlindnessComponent.cs b/Content.Shared/Traits/Assorted/PermanentBlindnessComponent.cs new file mode 100644 index 0000000000..2396ff3967 --- /dev/null +++ b/Content.Shared/Traits/Assorted/PermanentBlindnessComponent.cs @@ -0,0 +1,12 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Traits.Assorted; + +/// +/// This is used for making something blind forever. +/// +[RegisterComponent, NetworkedComponent] +public sealed class PermanentBlindnessComponent : Component +{ +} + diff --git a/Content.Shared/Traits/Assorted/PermanentBlindnessSystem.cs b/Content.Shared/Traits/Assorted/PermanentBlindnessSystem.cs new file mode 100644 index 0000000000..448433be39 --- /dev/null +++ b/Content.Shared/Traits/Assorted/PermanentBlindnessSystem.cs @@ -0,0 +1,41 @@ +using Content.Shared.Examine; +using Content.Shared.Eye.Blinding; +using Content.Shared.IdentityManagement; +using Robust.Shared.Network; + +namespace Content.Shared.Traits.Assorted; + +/// +/// This handles permanent blindness, both the examine and the actual effect. +/// +public sealed class PermanentBlindnessSystem : EntitySystem +{ + [Dependency] private readonly INetManager _net = default!; + [Dependency] private readonly SharedBlindingSystem _blinding = default!; + + /// + public override void Initialize() + { + SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnExamined); + } + + private void OnExamined(EntityUid uid, PermanentBlindnessComponent component, ExaminedEvent args) + { + if (args.IsInDetailsRange && !_net.IsClient) + { + args.PushMarkup(Loc.GetString("permanent-blindness-trait-examined", ("target", Identity.Entity(uid, EntityManager)))); + } + } + + private void OnShutdown(EntityUid uid, PermanentBlindnessComponent component, ComponentShutdown args) + { + _blinding.AdjustBlindSources(uid, false); + } + + private void OnStartup(EntityUid uid, PermanentBlindnessComponent component, ComponentStartup args) + { + _blinding.AdjustBlindSources(uid, true); + } +} diff --git a/Resources/Locale/en-US/traits/traits.ftl b/Resources/Locale/en-US/traits/traits.ftl new file mode 100644 index 0000000000..08df78b1ac --- /dev/null +++ b/Resources/Locale/en-US/traits/traits.ftl @@ -0,0 +1 @@ +permanent-blindness-trait-examined = [color=lightblue]{CAPITALIZE(POSS-ADJ($target))} eyes are glassy and unfocused. It doesn't seem like {SUBJECT($target)} can see you.[/color] diff --git a/Resources/Prototypes/Traits/disabilities.yml b/Resources/Prototypes/Traits/disabilities.yml new file mode 100644 index 0000000000..365b896608 --- /dev/null +++ b/Resources/Prototypes/Traits/disabilities.yml @@ -0,0 +1,19 @@ +- type: trait + id: Blindness + name: Blindness + components: + - type: PermanentBlindness + +- type: trait + id: Narcolepsy + name: Narcolepsy + components: + - type: Narcolepsy + timeBetweenIncidents: 300, 600 + durationOfIncident: 10, 30 + +- type: trait + id: Pacifist + name: Pacifist + components: + - type: Pacifist diff --git a/Resources/Prototypes/Traits/inconveniences.yml b/Resources/Prototypes/Traits/inconveniences.yml new file mode 100644 index 0000000000..dde4135a7d --- /dev/null +++ b/Resources/Prototypes/Traits/inconveniences.yml @@ -0,0 +1,10 @@ +- type: trait + id: UncontrollableSneezing + name: Runny nose + components: + - type: UncontrollableSnough + snoughSound: + collection: Sneezes + params: + variation: 0.2 + timeBetweenIncidents: 0.3, 300