diff --git a/Content.Server/Atmos/Miasma/MiasmaSystem.cs b/Content.Server/Atmos/Miasma/MiasmaSystem.cs index e945840821..a735d2fbe7 100644 --- a/Content.Server/Atmos/Miasma/MiasmaSystem.cs +++ b/Content.Server/Atmos/Miasma/MiasmaSystem.cs @@ -45,7 +45,8 @@ namespace Content.Server.Atmos.Miasma "VanAusdallsRobovirus", "BleedersBite", "Plague", - "TongueTwister" + "TongueTwister", + "MemeticAmirmir" }; /// diff --git a/Content.Server/Atmos/Portable/PortableScrubberComponent.cs b/Content.Server/Atmos/Portable/PortableScrubberComponent.cs index ac0ffdc226..a3764da8a2 100644 --- a/Content.Server/Atmos/Portable/PortableScrubberComponent.cs +++ b/Content.Server/Atmos/Portable/PortableScrubberComponent.cs @@ -28,7 +28,8 @@ namespace Content.Server.Atmos.Portable Gas.Plasma, Gas.Tritium, Gas.WaterVapor, - Gas.Miasma + Gas.Miasma, + Gas.NitrousOxide }; /// diff --git a/Content.Server/Bed/BedSystem.cs b/Content.Server/Bed/BedSystem.cs index ff890495fe..8ed37d8313 100644 --- a/Content.Server/Bed/BedSystem.cs +++ b/Content.Server/Bed/BedSystem.cs @@ -5,17 +5,26 @@ using Content.Server.Body.Systems; using Content.Shared.Buckle.Components; using Content.Shared.Body.Components; using Content.Shared.Bed; +using Content.Shared.Bed.Sleep; +using Content.Server.Bed.Sleep; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Shared.Emag.Systems; using Content.Shared.MobState.Components; +using Content.Server.Actions; +using Content.Server.MobState; +using Content.Shared.Actions.ActionTypes; +using Robust.Shared.Prototypes; namespace Content.Server.Bed { public sealed class BedSystem : EntitySystem { [Dependency] private readonly DamageableSystem _damageableSystem = default!; - + [Dependency] private readonly ActionsSystem _actionsSystem = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly SleepingSystem _sleepingSystem = default!; + [Dependency] private readonly MobStateSystem _mobStateSystem = default!; public override void Initialize() { base.Initialize(); @@ -27,12 +36,19 @@ namespace Content.Server.Bed private void ManageUpdateList(EntityUid uid, HealOnBuckleComponent component, BuckleChangeEvent args) { + _prototypeManager.TryIndex("Sleep", out var sleepAction); if (args.Buckling) { AddComp(uid); + if (sleepAction != null) + _actionsSystem.AddAction(args.BuckledEntity, new InstantAction(sleepAction), null); return; } + if (sleepAction != null) + _actionsSystem.RemoveAction(args.BuckledEntity, sleepAction, null); + + _sleepingSystem.TryWaking(args.BuckledEntity); RemComp(uid); component.Accumulator = 0; } @@ -52,13 +68,16 @@ namespace Content.Server.Bed if (strapComponent.BuckledEntities.Count == 0) continue; - var mobStateQuery = GetEntityQuery(); - foreach (var healedEntity in strapComponent.BuckledEntities) { - if (mobStateQuery.TryGetComponent(healedEntity, out var state) && state.IsDead()) + if (_mobStateSystem.IsDead(healedEntity)) continue; + var damage = bedComponent.Damage; + + if (HasComp(healedEntity)) + damage *= bedComponent.SleepMultiplier; + _damageableSystem.TryChangeDamage(healedEntity, bedComponent.Damage, true); } } diff --git a/Content.Server/Bed/Components/HealOnBuckle.cs b/Content.Server/Bed/Components/HealOnBuckleComponent.cs similarity index 86% rename from Content.Server/Bed/Components/HealOnBuckle.cs rename to Content.Server/Bed/Components/HealOnBuckleComponent.cs index 51428690aa..5e102c4e08 100644 --- a/Content.Server/Bed/Components/HealOnBuckle.cs +++ b/Content.Server/Bed/Components/HealOnBuckleComponent.cs @@ -12,6 +12,9 @@ namespace Content.Server.Bed.Components [DataField("healTime", required: false)] [ViewVariables(VVAccess.ReadWrite)] public float HealTime = 1f; // How often the bed applies the damage + + [DataField("sleepMultiplier")] + public float SleepMultiplier = 3f; public float Accumulator = 0f; //Time accumulated } } diff --git a/Content.Server/Bed/Sleep/SleepingSystem.cs b/Content.Server/Bed/Sleep/SleepingSystem.cs new file mode 100644 index 0000000000..f690d73d11 --- /dev/null +++ b/Content.Server/Bed/Sleep/SleepingSystem.cs @@ -0,0 +1,198 @@ +using Content.Shared.Stunnable; +using Content.Shared.MobState.Components; +using Content.Shared.Bed.Sleep; +using Content.Shared.Damage; +using Content.Server.Actions; +using Content.Shared.Actions.ActionTypes; +using Robust.Shared.Prototypes; +using Content.Shared.Sound; +using Robust.Shared.Timing; +using Content.Shared.MobState; +using Content.Server.MobState; +using Content.Server.Sound.Components; +using Content.Shared.Verbs; +using Content.Shared.Interaction; +using Robust.Shared.Audio; +using Robust.Shared.Player; +using Content.Shared.Audio; +using Content.Server.Popups; +using Content.Shared.Examine; +using Content.Shared.IdentityManagement; +using Robust.Shared.Random; + +namespace Content.Server.Bed.Sleep +{ + public sealed class SleepingSystem : EntitySystem + { + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly ActionsSystem _actionsSystem = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly MobStateSystem _mobStateSystem = default!; + [Dependency] private readonly PopupSystem _popupSystem = default!; + + [Dependency] private readonly IRobustRandom _robustRandom = default!; + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnSleepStateChanged); + SubscribeLocalEvent(OnDamageChanged); + SubscribeLocalEvent(OnSleepAction); + SubscribeLocalEvent(OnWakeAction); + SubscribeLocalEvent(OnMobStateChanged); + SubscribeLocalEvent>(AddWakeVerb); + SubscribeLocalEvent(OnInteractHand); + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnInit); + } + + /// + /// when sleeping component is added or removed, we do some stuff with other components. + /// + private void OnSleepStateChanged(EntityUid uid, MobStateComponent component, SleepStateChangedEvent args) + { + _prototypeManager.TryIndex("Wake", out var wakeAction); + if (args.FellAsleep) + { + EnsureComp(uid); + EnsureComp(uid); + + var emitSound = EnsureComp(uid); + emitSound.Sound = new SoundCollectionSpecifier("Snores"); + emitSound.PlayChance = 0.33f; + emitSound.RollInterval = 5f; + emitSound.PopUp = "sleep-onomatopoeia"; + emitSound.PitchVariation = 0.2f; + + if (wakeAction != null) + { + var wakeInstance = new InstantAction(wakeAction); + wakeInstance.Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + TimeSpan.FromSeconds(15)); + _actionsSystem.AddAction(uid, wakeInstance, null); + } + return; + } + if (wakeAction != null) + _actionsSystem.RemoveAction(uid, wakeAction); + + RemComp(uid); + RemComp(uid); + RemComp(uid); + } + + /// + /// Wake up if we take an instance of more than 2 damage. + /// + private void OnDamageChanged(EntityUid uid, SleepingComponent component, DamageChangedEvent args) + { + if (!args.DamageIncreased || args.DamageDelta == null) + return; + + if (args.DamageDelta.Total >= component.WakeThreshold) + TryWaking(uid); + } + + private void OnSleepAction(EntityUid uid, MobStateComponent component, SleepActionEvent args) + { + TrySleeping(uid); + } + + private void OnWakeAction(EntityUid uid, MobStateComponent component, WakeActionEvent args) + { + TryWaking(uid); + } + + /// + /// In crit, we wake up if we are not being forced to sleep. + /// And, you can't sleep when dead... + /// + private void OnMobStateChanged(EntityUid uid, SleepingComponent component, MobStateChangedEvent args) + { + if (_mobStateSystem.IsCritical(uid) && !HasComp(uid)) + { + RemComp(uid); + return; + } + + if (_mobStateSystem.IsDead(uid)) + RemComp(uid); + } + + private void AddWakeVerb(EntityUid uid, SleepingComponent component, GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess) + return; + + AlternativeVerb verb = new() + { + Act = () => + { + TryWaking(args.Target, user: args.User); + }, + Text = Loc.GetString("action-name-wake"), + Priority = 2 + }; + + args.Verbs.Add(verb); + } + + /// + /// When you click on a sleeping person with an empty hand, try to wake them. + /// + private void OnInteractHand(EntityUid uid, SleepingComponent component, InteractHandEvent args) + { + args.Handled = true; + TryWaking(args.Target, user: args.User); + } + + private void OnExamined(EntityUid uid, SleepingComponent component, ExaminedEvent args) + { + if (args.IsInDetailsRange) + { + args.PushMarkup(Loc.GetString("sleep-examined", ("target", Identity.Entity(uid, EntityManager)))); + } + } + private void OnInit(EntityUid uid, ForcedSleepingComponent component, ComponentInit args) + { + TrySleeping(uid); + } + + /// + /// Try sleeping. Only mobs can sleep. + /// + public bool TrySleeping(EntityUid uid) + { + if (!HasComp(uid)) + return false; + + if (_prototypeManager.TryIndex("Sleep", out var sleepAction)) + _actionsSystem.RemoveAction(uid, sleepAction); + + EnsureComp(uid); + return true; + } + + /// + /// Try to wake up. + /// + public bool TryWaking(EntityUid uid, bool force = false, EntityUid? user = null) + { + if (!force && HasComp(uid)) + { + if (user != null) + { + SoundSystem.Play("/Audio/Effects/thudswoosh.ogg", Filter.Pvs(uid), uid, AudioHelpers.WithVariation(0.05f, _robustRandom)); + _popupSystem.PopupEntity(Loc.GetString("wake-other-failure", ("target", Identity.Entity(uid, EntityManager))), uid, Filter.Entities(user.Value), Shared.Popups.PopupType.SmallCaution); + } + return false; + } + + if (user != null) + { + SoundSystem.Play("/Audio/Effects/thudswoosh.ogg", Filter.Pvs(uid), uid, AudioHelpers.WithVariation(0.05f, _robustRandom)); + _popupSystem.PopupEntity(Loc.GetString("wake-other-success", ("target", Identity.Entity(uid, EntityManager))), uid, Filter.Entities(user.Value)); + } + RemComp(uid); + return true; + } + } +} diff --git a/Content.Server/Buckle/Components/BuckleComponent.cs b/Content.Server/Buckle/Components/BuckleComponent.cs index 38a055b001..493767fd93 100644 --- a/Content.Server/Buckle/Components/BuckleComponent.cs +++ b/Content.Server/Buckle/Components/BuckleComponent.cs @@ -18,6 +18,7 @@ using Robust.Shared.Containers; using Robust.Shared.Player; using Robust.Shared.Timing; using Content.Shared.IdentityManagement; +using Content.Shared.Bed.Sleep; namespace Content.Server.Buckle.Components { @@ -264,6 +265,9 @@ namespace Content.Server.Buckle.Components { return false; } + + if (EntMan.TryGetComponent(Owner, out var sleeping) && Owner == user) + return false; // If the strap is a vehicle and the rider is not the person unbuckling, return. if (EntMan.TryGetComponent(oldBuckledTo.Owner, out var vehicle) && vehicle.Rider != user) diff --git a/Content.Server/Disease/Cures/DiseaseBedrestCure.cs b/Content.Server/Disease/Cures/DiseaseBedrestCure.cs index 0c60307dc8..ceb7455b81 100644 --- a/Content.Server/Disease/Cures/DiseaseBedrestCure.cs +++ b/Content.Server/Disease/Cures/DiseaseBedrestCure.cs @@ -1,6 +1,7 @@ using Content.Shared.Disease; using Content.Server.Buckle.Components; using Content.Server.Bed.Components; +using Content.Shared.Bed.Sleep; namespace Content.Server.Disease.Cures { @@ -12,6 +13,11 @@ namespace Content.Server.Disease.Cures { [ViewVariables(VVAccess.ReadWrite)] public int Ticker = 0; + + /// How many extra ticks you get for sleeping. + [DataField("sleepMultiplier")] + public int SleepMultiplier = 3; + [DataField("maxLength", required: true)] [ViewVariables(VVAccess.ReadWrite)] public int MaxLength = 60; @@ -21,14 +27,19 @@ namespace Content.Server.Disease.Cures if (!args.EntityManager.TryGetComponent(args.DiseasedEntity, out var buckle) || !args.EntityManager.HasComponent(buckle.BuckledTo?.Owner)) return false; + + var ticks = 1; + if (args.EntityManager.HasComponent(args.DiseasedEntity)) + ticks *= SleepMultiplier; + if (buckle.Buckled) - Ticker++; + Ticker += ticks; return Ticker >= MaxLength; } public override string CureText() { - return (Loc.GetString("diagnoser-cure-bedrest", ("time", MaxLength))); + return (Loc.GetString("diagnoser-cure-bedrest", ("time", MaxLength), ("sleep", (MaxLength / SleepMultiplier)))); } } } diff --git a/Content.Server/Disease/DiseaseSystem.cs b/Content.Server/Disease/DiseaseSystem.cs index 1f89f0e900..f60b3fe346 100644 --- a/Content.Server/Disease/DiseaseSystem.cs +++ b/Content.Server/Disease/DiseaseSystem.cs @@ -1,5 +1,4 @@ using System.Threading; -using Content.Server.Chat; using Content.Shared.Disease; using Content.Shared.Disease.Components; using Content.Server.Disease.Components; @@ -20,6 +19,8 @@ using Content.Shared.Inventory.Events; using Content.Server.Nutrition.EntitySystems; using Robust.Shared.Utility; using Content.Shared.IdentityManagement; +using Content.Shared.Item; +using Content.Server.MobState; namespace Content.Server.Disease { @@ -37,14 +38,14 @@ namespace Content.Server.Disease [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; [Dependency] private readonly InventorySystem _inventorySystem = default!; - + [Dependency] private readonly MobStateSystem _mobStateSystem = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnTryCureDisease); - SubscribeLocalEvent(OnInteractDiseasedHand); - SubscribeLocalEvent(OnInteractDiseasedUsing); + SubscribeLocalEvent(OnUserInteractDiseased); + SubscribeLocalEvent(OnTargetInteractDiseased); SubscribeLocalEvent(OnEntitySpeak); SubscribeLocalEvent(OnEquipped); SubscribeLocalEvent(OnUnequipped); @@ -88,7 +89,7 @@ namespace Content.Server.Disease { DebugTools.Assert(carrierComp.Diseases.Count > 0); - if (mobState.IsDead()) + if (_mobStateSystem.IsDead(mobState.Owner, mobState)) { if (_random.Prob(0.005f * frameTime)) //Mean time to remove is 200 seconds per disease CureDisease(carrierComp, _random.Pick(carrierComp.Diseases)); @@ -246,21 +247,19 @@ namespace Content.Server.Disease } /// - /// Called when someone interacts with a diseased person with an empty hand - /// to check if they get infected + /// When a diseased person interacts with something, check infection. /// - private void OnInteractDiseasedHand(EntityUid uid, DiseasedComponent component, InteractHandEvent args) + private void OnUserInteractDiseased(EntityUid uid, DiseasedComponent component, UserInteractedWithItemEvent args) { - InteractWithDiseased(args.Target, args.User); + InteractWithDiseased(args.User, args.Item); } /// - /// Called when someone interacts with a diseased person with any object - /// to check if they get infected + /// When a diseased person is interacted with, check infection. /// - private void OnInteractDiseasedUsing(EntityUid uid, DiseasedComponent component, InteractUsingEvent args) + private void OnTargetInteractDiseased(EntityUid uid, DiseasedComponent component, ItemInteractedWithEvent args) { - InteractWithDiseased(args.Target, args.User); + InteractWithDiseased(args.Item, args.User); } private void OnEntitySpeak(EntityUid uid, DiseasedComponent component, EntitySpokeEvent args) diff --git a/Content.Server/Interaction/InteractionPopupSystem.cs b/Content.Server/Interaction/InteractionPopupSystem.cs index 8aca8656bc..f643213ca3 100644 --- a/Content.Server/Interaction/InteractionPopupSystem.cs +++ b/Content.Server/Interaction/InteractionPopupSystem.cs @@ -7,7 +7,7 @@ using Robust.Shared.Audio; using Robust.Shared.Player; using Robust.Shared.Timing; using Robust.Shared.Random; - +using Content.Shared.Bed.Sleep; namespace Content.Server.Interaction; @@ -28,6 +28,10 @@ public sealed class InteractionPopupSystem : EntitySystem if (args.Handled || args.User == args.Target) return; + //Handling does nothing and this thing annoyingly plays way too often. + if (HasComp(uid)) + return; + var curTime = _gameTiming.CurTime; if (curTime < component.LastInteractTime + component.InteractDelay) diff --git a/Content.Server/Sound/Components/SpamEmitSoundComponent.cs b/Content.Server/Sound/Components/SpamEmitSoundComponent.cs index d839dc2f91..3378421be9 100644 --- a/Content.Server/Sound/Components/SpamEmitSoundComponent.cs +++ b/Content.Server/Sound/Components/SpamEmitSoundComponent.cs @@ -14,5 +14,9 @@ namespace Content.Server.Sound.Components [DataField("playChance")] public float PlayChance = 0.5f; + + // Always Pvs. + [DataField("popUp")] + public string? PopUp; } } diff --git a/Content.Server/Sound/EmitSoundSystem.cs b/Content.Server/Sound/EmitSoundSystem.cs index 7e7b458b85..f05cb4e152 100644 --- a/Content.Server/Sound/EmitSoundSystem.cs +++ b/Content.Server/Sound/EmitSoundSystem.cs @@ -12,6 +12,7 @@ using Robust.Shared.Audio; using Robust.Shared.Map; using Robust.Shared.Player; using Robust.Shared.Random; +using Content.Server.Popups; namespace Content.Server.Sound { @@ -24,6 +25,7 @@ namespace Content.Server.Sound [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly ITileDefinitionManager _tileDefMan = default!; + [Dependency] private readonly PopupSystem _popupSystem = default!; /// @@ -41,6 +43,8 @@ namespace Content.Server.Sound if (_random.Prob(soundSpammer.PlayChance)) { + if (soundSpammer.PopUp != null) + _popupSystem.PopupEntity(Loc.GetString(soundSpammer.PopUp), soundSpammer.Owner, Filter.Pvs(soundSpammer.Owner)); TryEmitSound(soundSpammer); } } diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Components/GasArtifactComponent.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Components/GasArtifactComponent.cs index e68254d0b3..e99e3d078c 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Components/GasArtifactComponent.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Components/GasArtifactComponent.cs @@ -28,6 +28,7 @@ public sealed class GasArtifactComponent : Component Gas.CarbonDioxide, Gas.Tritium, Gas.Miasma, + Gas.NitrousOxide, }; /// diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/DiseaseArtifactSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/DiseaseArtifactSystem.cs index 494a2dfd5d..1cde45c6d7 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/DiseaseArtifactSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/DiseaseArtifactSystem.cs @@ -28,6 +28,7 @@ namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems "OwOnavirus", "BleedersBite", "Ultragigacancer", + "MemeticAmirmir", "AMIV" }; diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Components/ArtifactGasTriggerComponent.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Components/ArtifactGasTriggerComponent.cs index 620ad91978..a5d0503ed0 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Components/ArtifactGasTriggerComponent.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Components/ArtifactGasTriggerComponent.cs @@ -18,7 +18,8 @@ public sealed class ArtifactGasTriggerComponent : Component Gas.Plasma, Gas.Nitrogen, Gas.CarbonDioxide, - Gas.Miasma + Gas.Miasma, + Gas.NitrousOxide, }; /// diff --git a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs index f12a0761b5..f2e47ad8eb 100644 --- a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs +++ b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs @@ -181,8 +181,10 @@ namespace Content.Shared.ActionBlocker private void InteractWithItem(EntityUid user, EntityUid item) { - var itemEvent = new UserInteractedWithItemEvent(user, item); - RaiseLocalEvent(user, itemEvent); + var userEvent = new UserInteractedWithItemEvent(user, item); + RaiseLocalEvent(user, userEvent); + var itemEvent = new ItemInteractedWithEvent(user, item); + RaiseLocalEvent(item, itemEvent); } } } diff --git a/Content.Shared/Atmos/Atmospherics.cs b/Content.Shared/Atmos/Atmospherics.cs index 61d57ef892..6f977662a9 100644 --- a/Content.Shared/Atmos/Atmospherics.cs +++ b/Content.Shared/Atmos/Atmospherics.cs @@ -168,7 +168,7 @@ namespace Content.Shared.Atmos /// /// Total number of gases. Increase this if you want to add more! /// - public const int TotalNumberOfGases = 7; + public const int TotalNumberOfGases = 8; /// /// This is the actual length of the gases arrays in mixtures. @@ -285,6 +285,7 @@ namespace Content.Shared.Atmos Plasma = 3, Tritium = 4, WaterVapor = 5, - Miasma = 6 + Miasma = 6, + NitrousOxide = 7 } } diff --git a/Content.Shared/Atmos/Piping/Unary/Components/SharedVentScrubberComponent.cs b/Content.Shared/Atmos/Piping/Unary/Components/SharedVentScrubberComponent.cs index 08b7db440a..ee5d5774b3 100644 --- a/Content.Shared/Atmos/Piping/Unary/Components/SharedVentScrubberComponent.cs +++ b/Content.Shared/Atmos/Piping/Unary/Components/SharedVentScrubberComponent.cs @@ -20,7 +20,8 @@ namespace Content.Shared.Atmos.Piping.Unary.Components Gas.Plasma, Gas.Tritium, Gas.WaterVapor, - Gas.Miasma + Gas.Miasma, + Gas.NitrousOxide }; // Presets for 'dumb' air alarm modes diff --git a/Content.Shared/Bed/Sleep/ForcedSleepingComponent.cs b/Content.Shared/Bed/Sleep/ForcedSleepingComponent.cs new file mode 100644 index 0000000000..a703fa9bcb --- /dev/null +++ b/Content.Shared/Bed/Sleep/ForcedSleepingComponent.cs @@ -0,0 +1,11 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Bed.Sleep +{ + [NetworkedComponent, RegisterComponent] + /// + /// Prevents waking up. Use as a status effect. + /// + public sealed class ForcedSleepingComponent : Component + {} +} diff --git a/Content.Shared/Bed/Sleep/SharedSleepingSystem.cs b/Content.Shared/Bed/Sleep/SharedSleepingSystem.cs new file mode 100644 index 0000000000..7d7414a98d --- /dev/null +++ b/Content.Shared/Bed/Sleep/SharedSleepingSystem.cs @@ -0,0 +1,56 @@ +using Content.Shared.Eye.Blinding; +using Content.Shared.Speech; +using Content.Shared.Actions; +using Content.Shared.Bed.Sleep; + +namespace Content.Server.Bed.Sleep +{ + public sealed class SharedSleepingSystem : EntitySystem + { + [Dependency] private readonly SharedBlindingSystem _blindingSystem = default!; + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnSpeakAttempt); + } + + private void OnInit(EntityUid uid, SleepingComponent component, ComponentInit args) + { + var ev = new SleepStateChangedEvent(true); + RaiseLocalEvent(uid, ev, false); + _blindingSystem.AdjustBlindSources(uid, true); + } + + private void OnShutdown(EntityUid uid, SleepingComponent component, ComponentShutdown args) + { + var ev = new SleepStateChangedEvent(false); + RaiseLocalEvent(uid, ev, false); + _blindingSystem.AdjustBlindSources(uid, false); + } + + private void OnSpeakAttempt(EntityUid uid, SleepingComponent component, SpeakAttemptEvent args) + { + args.Cancel(); + } + } +} + + +public sealed class SleepActionEvent : InstantActionEvent {} + +public sealed class WakeActionEvent : InstantActionEvent {} + +/// +/// Raised on an entity when they fall asleep or wake up. +/// +public sealed class SleepStateChangedEvent : EntityEventArgs +{ + public bool FellAsleep = false; + + public SleepStateChangedEvent(bool fellAsleep) + { + FellAsleep = fellAsleep; + } +} diff --git a/Content.Shared/Bed/Sleep/SleepingComponent.cs b/Content.Shared/Bed/Sleep/SleepingComponent.cs new file mode 100644 index 0000000000..b35132929c --- /dev/null +++ b/Content.Shared/Bed/Sleep/SleepingComponent.cs @@ -0,0 +1,14 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Bed.Sleep; + +[NetworkedComponent, RegisterComponent] +/// +/// Added to entities when they go to sleep. +/// +public sealed class SleepingComponent : Component +{ + // How much damage of any type it takes to wake this entity. + [DataField("wakeThreshold")] + public float WakeThreshold = 2; +} diff --git a/Content.Shared/Item/ItemInteractedWithEvent.cs b/Content.Shared/Item/ItemInteractedWithEvent.cs new file mode 100644 index 0000000000..28611d291a --- /dev/null +++ b/Content.Shared/Item/ItemInteractedWithEvent.cs @@ -0,0 +1,17 @@ +namespace Content.Shared.Item; + +/// +/// Raised on the item after they do any sort of interaction with an item, +/// useful for when you want a component on the user to do something to the user +/// E.g. forensics, disease, etc. +/// +public sealed class ItemInteractedWithEvent : EntityEventArgs +{ + public EntityUid User; + public EntityUid Item; + public ItemInteractedWithEvent(EntityUid user, EntityUid item) + { + User = user; + Item = item; + } +} diff --git a/Content.Shared/Stunnable/SharedStunSystem.cs b/Content.Shared/Stunnable/SharedStunSystem.cs index f778f71b40..8aca962027 100644 --- a/Content.Shared/Stunnable/SharedStunSystem.cs +++ b/Content.Shared/Stunnable/SharedStunSystem.cs @@ -5,7 +5,7 @@ using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Inventory.Events; using Content.Shared.Item; -using Content.Shared.Movement; +using Content.Shared.Bed.Sleep; using Content.Shared.Movement.Events; using Content.Shared.Movement.Systems; using Content.Shared.Standing; @@ -198,6 +198,9 @@ namespace Content.Shared.Stunnable if (args.Handled || knocked.HelpTimer > 0f) return; + if (HasComp(uid)) + return; + // Set it to half the help interval so helping is actually useful... knocked.HelpTimer = knocked.HelpInterval/2f; diff --git a/Resources/Audio/Effects/Diseases/license.txt b/Resources/Audio/Effects/Diseases/license.txt index 96816fdb83..16aa10dbd9 100644 --- a/Resources/Audio/Effects/Diseases/license.txt +++ b/Resources/Audio/Effects/Diseases/license.txt @@ -6,3 +6,6 @@ monkey1.ogg taken from https://freesound.org/people/TRAVELcandies/sounds/423396/ monkey2.ogg taken from https://freesound.org/people/Archeos/sounds/325549/ sneeze2.ogg taken from https://freesound.org/people/InspectorJ/sounds/352177/ vomiting.ogg taken from https://freesound.org/people/vikuserro/sounds/246308/ +yawn1.ogg taken from https://freesound.org/people/ckvoiceover/sounds/401338/ user ckvoiceover CC-3.0 +yawn2.ogg taken from https://freesound.org/people/Reitanna/sounds/252239/ user reitanna CC-0 +snore1, snore2, snore3.ogg taken from https://freesound.org/people/mattyharm/sounds/432995/ user mattyharm CC-0 diff --git a/Resources/Audio/Effects/Diseases/snore1.ogg b/Resources/Audio/Effects/Diseases/snore1.ogg new file mode 100644 index 0000000000..314b6cab31 Binary files /dev/null and b/Resources/Audio/Effects/Diseases/snore1.ogg differ diff --git a/Resources/Audio/Effects/Diseases/snore2.ogg b/Resources/Audio/Effects/Diseases/snore2.ogg new file mode 100644 index 0000000000..94c7b155a5 Binary files /dev/null and b/Resources/Audio/Effects/Diseases/snore2.ogg differ diff --git a/Resources/Audio/Effects/Diseases/snore3.ogg b/Resources/Audio/Effects/Diseases/snore3.ogg new file mode 100644 index 0000000000..468e7e6c80 Binary files /dev/null and b/Resources/Audio/Effects/Diseases/snore3.ogg differ diff --git a/Resources/Audio/Effects/Diseases/yawn1.ogg b/Resources/Audio/Effects/Diseases/yawn1.ogg new file mode 100644 index 0000000000..51390959cb Binary files /dev/null and b/Resources/Audio/Effects/Diseases/yawn1.ogg differ diff --git a/Resources/Audio/Effects/Diseases/yawn2.ogg b/Resources/Audio/Effects/Diseases/yawn2.ogg new file mode 100644 index 0000000000..485c6462c6 Binary files /dev/null and b/Resources/Audio/Effects/Diseases/yawn2.ogg differ diff --git a/Resources/Locale/en-US/actions/actions/sleep.ftl b/Resources/Locale/en-US/actions/actions/sleep.ftl new file mode 100644 index 0000000000..ff3c8c04a7 --- /dev/null +++ b/Resources/Locale/en-US/actions/actions/sleep.ftl @@ -0,0 +1,9 @@ +action-name-sleep = Sleep +action-desc-sleep = Go to sleep. +action-name-wake = Wake up +action-desc-wake = Stop sleeping. +sleep-onomatopoeia = Zzz... +sleep-examined = [color=lightblue]{CAPITALIZE(SUBJECT($target))} {CONJUGATE-BE($target)} asleep.[/color] + +wake-other-success = You shake {THE($target)} awake. +wake-other-failure = You shake {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} not waking up. diff --git a/Resources/Locale/en-US/chemistry/reagent-effects.ftl b/Resources/Locale/en-US/chemistry/reagent-effects.ftl new file mode 100644 index 0000000000..537770b35a --- /dev/null +++ b/Resources/Locale/en-US/chemistry/reagent-effects.ftl @@ -0,0 +1 @@ +effect-sleepy = You feel a bit sleepy. diff --git a/Resources/Locale/en-US/disease/diagnoser.ftl b/Resources/Locale/en-US/disease/diagnoser.ftl index 3d7dddff21..70d1bde34e 100644 --- a/Resources/Locale/en-US/disease/diagnoser.ftl +++ b/Resources/Locale/en-US/disease/diagnoser.ftl @@ -12,7 +12,7 @@ diagnoser-disease-report-cureresist-medium = Spaceacillin Resistance: [color=ora diagnoser-disease-report-cureresist-high = Spaceacillin Resistance: [color=red]High[/color] diagnoser-cure-none = The disease has no specific cures. diagnoser-cure-has = The disease has the following cures: -diagnoser-cure-bedrest = Rest in bed for {$time} seconds. +diagnoser-cure-bedrest = Rest in bed for {$time} seconds, or {$sleep} seconds if sleeping. diagnoser-cure-reagent = Consume at least {$units}u of {$reagent}. diagnoser-cure-wait = It will go away on its own after {$time} seconds. diagnoser-cure-temp = Reach a body temperature below {$max}°K or above {$min}°K. diff --git a/Resources/Locale/en-US/disease/disease.ftl b/Resources/Locale/en-US/disease/disease.ftl index dc4d889593..1a2de90acc 100644 --- a/Resources/Locale/en-US/disease/disease.ftl +++ b/Resources/Locale/en-US/disease/disease.ftl @@ -3,6 +3,7 @@ disease-sick-generic = You feel sick. disease-sneeze = {CAPITALIZE($person)} sneezes. disease-cough = {CAPITALIZE($person)} coughs. disease-screech = {CAPITALIZE($person)} screeches. +disease-yawn = {CAPITALIZE($person)} yawns. disease-meow = {CAPITALIZE($person)} meows. disease-hiss = {CAPITALIZE($person)} hisses. disease-beep= {CAPITALIZE($person)} beeps. @@ -11,4 +12,4 @@ disease-banana-compulsion = You really want to eat some bananas. disease-beat-chest-compulsion = {CAPITALIZE(THE($person))} beats {POSS-ADJ($person)} chest. disease-vomit = {CAPITALIZE(THE($person))} vomits. disease-think = You feel like you can't think straight. -disease-polymorph = You feel your body twist and change form! \ No newline at end of file +disease-polymorph = You feel your body twist and change form! diff --git a/Resources/Locale/en-US/reagents/meta/gases.ftl b/Resources/Locale/en-US/reagents/meta/gases.ftl index f92a0b6ca4..9eedb29bc0 100644 --- a/Resources/Locale/en-US/reagents/meta/gases.ftl +++ b/Resources/Locale/en-US/reagents/meta/gases.ftl @@ -15,3 +15,6 @@ reagent-desc-nitrogen = A colorless, odorless unreactive gas. Highly stable. reagent-name-miasma = miasma reagent-desc-miasma = Uh oh, stinky! + +reagent-name-nitrous-oxide = nitrous oxide +reagent-desc-nitrous-oxide = You know how everything seems funnier when you're tired? Well... diff --git a/Resources/Locale/en-US/reagents/meta/toxins.ftl b/Resources/Locale/en-US/reagents/meta/toxins.ftl index 3d73bb0e23..85306dc2c5 100644 --- a/Resources/Locale/en-US/reagents/meta/toxins.ftl +++ b/Resources/Locale/en-US/reagents/meta/toxins.ftl @@ -10,6 +10,9 @@ reagent-desc-mold = Often found in dark, humid places or on old bread. reagent-name-polytrinic-acid = polytrinic acid reagent-desc-polytrinic-acid = An extremely corrosive chemical substance. The slightest touch of it will melt off most masks and headgear, and it deals extreme damage to anyone who comes directly into contact with it. +reagent-name-chloral-hydrate = chloral hydrate +reagent-desc-chloral-hydrate = In low doses, makes you drowsy. In higher doses, puts you to sleep. Overdoses deal toxin damage. + reagent-name-fluorosulfuric-acid = fluorosulfuric acid reagent-desc-fluorosulfuric-acid = An extremely corrosive chemical substance. diff --git a/Resources/Prototypes/Actions/types.yml b/Resources/Prototypes/Actions/types.yml index d30a32993c..b15692f104 100644 --- a/Resources/Prototypes/Actions/types.yml +++ b/Resources/Prototypes/Actions/types.yml @@ -77,3 +77,19 @@ icon: Objects/Consumable/Food/egg.rsi/icon.png useDelay: 60 serverEvent: !type:EggLayInstantActionEvent + +- type: instantAction + id: Sleep + name: action-name-sleep + description: action-desc-sleep + checkCanInteract: false + icon: Objects/Consumable/Food/egg.rsi/icon.png + event: !type:SleepActionEvent + +- type: instantAction + id: Wake + name: action-name-wake + description: action-desc-wake + icon: Objects/Consumable/Food/egg.rsi/icon.png + checkCanInteract: false + event: !type:WakeActionEvent diff --git a/Resources/Prototypes/Atmospherics/gases.yml b/Resources/Prototypes/Atmospherics/gases.yml index 6e3f4dfe43..05873f245c 100644 --- a/Resources/Prototypes/Atmospherics/gases.yml +++ b/Resources/Prototypes/Atmospherics/gases.yml @@ -68,3 +68,12 @@ gasOverlayState: miasma color: 56941E reagent: Miasma + +- type: gas + id: 7 + name: NitrousOxide + specificHeat: 40 + heatCapacityRatio: 1.3 + molarMass: 44 + color: 2887E8 + reagent: NitrousOxide diff --git a/Resources/Prototypes/Catalog/Fills/Items/gas_tanks.yml b/Resources/Prototypes/Catalog/Fills/Items/gas_tanks.yml index 79ca46cc40..e8c2cfd437 100644 --- a/Resources/Prototypes/Catalog/Fills/Items/gas_tanks.yml +++ b/Resources/Prototypes/Catalog/Fills/Items/gas_tanks.yml @@ -75,7 +75,7 @@ - 4.75217098 # oxygen - 17.8772147 # nitrogen temperature: 293.15 - + - type: entity id: NitrogenTankFilled parent: RedOxygenTankFilled @@ -91,6 +91,27 @@ - 22.6293856 # nitrogen temperature: 293.15 +- type: entity + id: NitrousOxideTankFilled + parent: NitrousOxideTank + suffix: Filled + name: nitrous oxide tank + components: + - type: GasTank + outputPressure: 101.325 + air: + volume: 70 + moles: + - 20.5 # oxygen + - 0 # CO2 + - 0 # Plasma + - 0 # Tritium + - 0 # Water vapor + - 0 # Miasma + - 2 # N2O + temperature: 293.15 + + - type: entity id: PlasmaTankFilled parent: PlasmaTank diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/medical.yml b/Resources/Prototypes/Catalog/Fills/Lockers/medical.yml index 8c55c4153e..356d79fe22 100644 --- a/Resources/Prototypes/Catalog/Fills/Lockers/medical.yml +++ b/Resources/Prototypes/Catalog/Fills/Lockers/medical.yml @@ -47,6 +47,8 @@ - id: UniformScrubsColorPurple prob: 0.05 orGroup: Surgshrubs + - id: NitrousOxideTankFilled + prob: 0.3 - id: ClothingMaskSterile - type: entity diff --git a/Resources/Prototypes/Diseases/infectious.yml b/Resources/Prototypes/Diseases/infectious.yml index 9cbb6896fa..21497a1250 100644 --- a/Resources/Prototypes/Diseases/infectious.yml +++ b/Resources/Prototypes/Diseases/infectious.yml @@ -190,7 +190,7 @@ probability: 0.000427 ## ~5% chance over 120 secs polymorphId: AMIVMorph polymorphMessage: disease-polymorph - polymorphSound: + polymorphSound: path: /Audio/Animals/monkey_scream.ogg stages: - 2 @@ -208,6 +208,22 @@ - 1 - 2 +- type: disease + id: MemeticAmirmir + name: Memetic Amirmir + effects: + - !type:DiseaseGenericStatusEffect + probability: 0.015 + key: ForcedSleep + component: ForcedSleeping + time: 3 + type: Add + - !type:DiseaseSnough + probability: 0.025 + snoughMessage: disease-yawn + snoughSound: + collection: Yawns + - type: disease id: BleedersBite name: Bleeder's Bite diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml b/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml index 993c76d55c..a5717cfb37 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml @@ -111,6 +111,7 @@ - SlowedDown - Stutter - Electrocution + - ForcedSleep - type: Body template: AnimalTemplate preset: AnimalPreset @@ -177,6 +178,7 @@ - SlowedDown - Stutter - Electrocution + - ForcedSleep - type: ThermalRegulator metabolismHeat: 800 radiatedHeat: 100 diff --git a/Resources/Prototypes/Entities/Mobs/Species/human.yml b/Resources/Prototypes/Entities/Mobs/Species/human.yml index 6ba8964a9e..a6dbeb0324 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/human.yml @@ -81,6 +81,7 @@ - SlurredSpeech - PressureImmunity - Muted + - ForcedSleep - type: DiseaseCarrier - type: Blindable # Other diff --git a/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml b/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml index d934756a06..f4232e8805 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml @@ -161,6 +161,25 @@ - Back - suitStorage +- type: entity + parent: GasTankBase + id: NitrousOxideTank + name: nitrous oxide tank + description: Contains a mixture of air and nitrous oxide. Make sure you don't refill it with pure N2O. + components: + - type: Sprite + sprite: Objects/Tanks/anesthetic.rsi + - type: GasTank + outputPressure: 101.325 + air: + volume: 70 + temperature: 293.15 + - type: Clothing + sprite: Objects/Tanks/anesthetic.rsi + Slots: + - Back + - suitStorage + - type: entity parent: GasTankBase id: PlasmaTank diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/miners.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/miners.yml index d55e480853..8ffc122857 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/miners.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/miners.yml @@ -90,3 +90,23 @@ components: - type: GasMiner spawnGas: WaterVapor + +- type: entity + name: Miasma gas miner + parent: GasMinerBase + id: GasMinerMiasma + placement: + mode: SnapgridCenter + components: + - type: GasMiner + spawnGas: Miasma + +- type: entity + name: Nitrous Oxide gas miner + parent: GasMinerBase + id: GasMinerNitrousOxide + placement: + mode: SnapgridCenter + components: + - type: GasMiner + spawnGas: NitrousOxide diff --git a/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml b/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml index 0645bb1542..ea927374ad 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml @@ -360,7 +360,7 @@ components: - type: Sprite layers: - - state: redws + - state: greenys - type: GasCanister gasMixture: volume: 1000 @@ -390,6 +390,44 @@ - !type:DoActsBehavior acts: [ "Destruction" ] +- type: entity + parent: GasCanister + id: NitrousOxideCanister + name: nitrous oxide canister + components: + - type: Sprite + layers: + - state: redws + - type: GasCanister + gasMixture: + volume: 1000 + moles: + - 0 # oxygen + - 0 # nitrogen + - 0 # CO2 + - 0 # Plasma + - 0 # Tritium + - 0 # Water vapor + - 0 # Miasma + - 1871.71051 # N2O + temperature: 293.15 + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 300 + behaviors: + - !type:PlaySoundBehavior + sound: + path: /Audio/Effects/metalbreak.ogg + - !type:SpawnEntitiesBehavior + spawn: + NitrousOxideCanisterBroken: + min: 1 + max: 1 + - !type:DoActsBehavior + acts: [ "Destruction" ] + # Broke Entities @@ -512,6 +550,15 @@ id: MiasmaCanisterBroken name: broken miasma canister noSpawn: true + components: + - type: Sprite + state: greenys-1 + +- type: entity + parent: GasCanisterBrokenBase + id: NitrousOxideCanisterBroken + name: broken nitrous oxide canister + noSpawn: true components: - type: Sprite state: redws-1 diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/air_alarm.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/air_alarm.yml index d07ac4ecee..cbd55c1f7c 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/air_alarm.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/air_alarm.yml @@ -27,6 +27,7 @@ Tritium: danger WaterVapor: danger Miasma: danger + NitrousOxide: danger - type: AtmosAlarmable alarmedBy: ["AirAlarm"] - type: AtmosDevice diff --git a/Resources/Prototypes/Reagents/gases.yml b/Resources/Prototypes/Reagents/gases.yml index c49c17b562..6e87919bf0 100644 --- a/Resources/Prototypes/Reagents/gases.yml +++ b/Resources/Prototypes/Reagents/gases.yml @@ -151,6 +151,13 @@ ratios: CarbonDioxide: 1.0 Nitrogen: -1.0 + - !type:ModifyLungGas + conditions: + - !type:OrganType + type: Slime + ratios: + NitrousOxide: 1.0 + Nitrogen: -1.0 - type: reagent id: Miasma @@ -215,3 +222,61 @@ Blunt: -4 Slash: -3 Piercing: -3 + +- type: reagent + id: NitrousOxide + name: reagent-name-nitrous-oxide + desc: reagent-desc-nitrous-oxide + physicalDesc: reagent-physical-desc-gaseous + color: "#808080" + boilingPoint: -88 + meltingPoint: -90 + metabolisms: + Gas: + effects: + - !type:PopupMessage + conditions: + - !type:ReagentThreshold + reagent: NitrousOxide + min: 0.5 + - !type:OrganType + type: Slime + shouldHave: false + type: Local + visualType: Medium + messages: [ "effect-sleepy" ] + probability: 0.1 + - !type:MovespeedModifier + conditions: + - !type:ReagentThreshold + reagent: NitrousOxide + min: 1 + - !type:OrganType + type: Slime + shouldHave: false + walkSpeedModifier: 0.65 + sprintSpeedModifier: 0.65 + - !type:GenericStatusEffect + conditions: + - !type:ReagentThreshold + reagent: NitrousOxide + min: 1.8 + - !type:OrganType + type: Slime + shouldHave: false + key: ForcedSleep + component: ForcedSleeping + time: 3 + type: Add + - !type:HealthChange + conditions: + - !type:ReagentThreshold + reagent: NitrousOxide + min: 3.5 + - !type:OrganType + type: Slime + shouldHave: false + ignoreResistances: true + damage: + types: + Poison: 0.25 diff --git a/Resources/Prototypes/Reagents/toxins.yml b/Resources/Prototypes/Reagents/toxins.yml index 9f0004e514..40dac0327a 100644 --- a/Resources/Prototypes/Reagents/toxins.yml +++ b/Resources/Prototypes/Reagents/toxins.yml @@ -44,6 +44,37 @@ probability: 0.33 +- type: reagent + id: ChloralHydrate + name: reagent-name-chloral-hydrate + group: Toxins + desc: reagent-desc-chloral-hydrate + color: "#000067" + physicalDesc: reagent-physical-desc-nondescript + metabolisms: + Poison: + effects: + - !type:MovespeedModifier + walkSpeedModifier: 0.65 + sprintSpeedModifier: 0.65 + - !type:GenericStatusEffect + conditions: + - !type:ReagentThreshold + reagent: ChloralHydrate + min: 15 + key: ForcedSleep + component: ForcedSleeping + refresh: false + type: Add + - !type:HealthChange + conditions: + - !type:ReagentThreshold + reagent: ChloralHydrate + min: 20 + damage: + types: + Poison: 1.5 + - type: reagent id: Mold name: reagent-name-mold @@ -69,6 +100,7 @@ - SpaceFlu - BirdFlew - Plague + - MemeticAmirmir - type: reagent id: PolytrinicAcid diff --git a/Resources/Prototypes/Recipes/Reactions/chemicals.yml b/Resources/Prototypes/Recipes/Reactions/chemicals.yml index ad9e0cbea8..38e625d02c 100644 --- a/Resources/Prototypes/Recipes/Reactions/chemicals.yml +++ b/Resources/Prototypes/Recipes/Reactions/chemicals.yml @@ -312,4 +312,17 @@ Carbon: amount: 1 products: - MuteToxin: 2 #Lower yield is intentional + MuteToxin: 2 + +- type: reaction + id: ChloralHydrate + impact: Medium + reactants: + Chlorine: + amount: 3 + Ethanol: + amount: 1 + Water: + amount: 1 + products: + ChloralHydrate: 1 diff --git a/Resources/Prototypes/SoundCollections/disease.yml b/Resources/Prototypes/SoundCollections/disease.yml index 63a50e9ec7..b4299e0c85 100644 --- a/Resources/Prototypes/SoundCollections/disease.yml +++ b/Resources/Prototypes/SoundCollections/disease.yml @@ -30,3 +30,16 @@ id: RobotBeeps files: - /Audio/Effects/Diseases/beepboop.ogg + +- type: soundCollection + id: Yawns + files: + - /Audio/Effects/Diseases/yawn1.ogg + - /Audio/Effects/Diseases/yawn2.ogg + +- type: soundCollection + id: Snores + files: + - /Audio/Effects/Diseases/snore1.ogg + - /Audio/Effects/Diseases/snore2.ogg + - /Audio/Effects/Diseases/snore3.ogg diff --git a/Resources/Prototypes/status_effects.yml b/Resources/Prototypes/status_effects.yml index eeb9b8c500..af8a3b4e6c 100644 --- a/Resources/Prototypes/status_effects.yml +++ b/Resources/Prototypes/status_effects.yml @@ -33,10 +33,13 @@ - type: statusEffect id: SlurredSpeech - + - type: statusEffect id: PressureImmunity - type: statusEffect id: Muted alert: Muted + +- type: statusEffect + id: ForcedSleep #I.e., they will not wake on damage or similar diff --git a/Resources/Textures/Structures/Storage/canister.rsi/greenys-1.png b/Resources/Textures/Structures/Storage/canister.rsi/greenys-1.png new file mode 100644 index 0000000000..ecc5294699 Binary files /dev/null and b/Resources/Textures/Structures/Storage/canister.rsi/greenys-1.png differ diff --git a/Resources/Textures/Structures/Storage/canister.rsi/greenys.png b/Resources/Textures/Structures/Storage/canister.rsi/greenys.png new file mode 100644 index 0000000000..a414a19281 Binary files /dev/null and b/Resources/Textures/Structures/Storage/canister.rsi/greenys.png differ diff --git a/Resources/Textures/Structures/Storage/canister.rsi/meta.json b/Resources/Textures/Structures/Storage/canister.rsi/meta.json index a0531e33d0..50ebcaa08b 100644 --- a/Resources/Textures/Structures/Storage/canister.rsi/meta.json +++ b/Resources/Textures/Structures/Storage/canister.rsi/meta.json @@ -82,6 +82,12 @@ { "name": "green-1" }, + { + "name": "greenys" + }, + { + "name": "greenys-1" + }, { "name": "darkblue" },