diff --git a/Content.Client/Bed/Components/StasisBedVisualsComponent.cs b/Content.Client/Bed/Components/StasisBedVisualsComponent.cs new file mode 100644 index 0000000000..8233a32b6f --- /dev/null +++ b/Content.Client/Bed/Components/StasisBedVisualsComponent.cs @@ -0,0 +1,5 @@ +namespace Content.Client.Bed; + +[RegisterComponent] +public sealed class StasisBedVisualsComponent : Component +{} diff --git a/Content.Client/Bed/StasisBedSystem.cs b/Content.Client/Bed/StasisBedSystem.cs new file mode 100644 index 0000000000..cde80c1686 --- /dev/null +++ b/Content.Client/Bed/StasisBedSystem.cs @@ -0,0 +1,22 @@ +using Content.Shared.Bed; +using Robust.Client.GameObjects; + +namespace Content.Client.Bed +{ + public sealed class StasisBedSystem : VisualizerSystem + { + protected override void OnAppearanceChange(EntityUid uid, StasisBedVisualsComponent component, ref AppearanceChangeEvent args) + { + if (TryComp(uid, out SpriteComponent? sprite) + && args.Component.TryGetData(StasisBedVisuals.IsOn, out bool isOn)) + { + sprite.LayerSetVisible(StasisBedVisualLayers.IsOn, isOn); + } + } + } + + public enum StasisBedVisualLayers : byte + { + IsOn, + } +} diff --git a/Content.Client/Entry/IgnoredComponents.cs b/Content.Client/Entry/IgnoredComponents.cs index ec340c623e..292bae52af 100644 --- a/Content.Client/Entry/IgnoredComponents.cs +++ b/Content.Client/Entry/IgnoredComponents.cs @@ -272,6 +272,8 @@ namespace Content.Client.Entry "BeingCloned", "Advertise", "Bible", + "HealOnBuckle", + "StasisBed", "PowerNetworkBattery", "BatteryCharger", "UnpoweredFlashlight", diff --git a/Content.Server/Bed/BedSystem.cs b/Content.Server/Bed/BedSystem.cs new file mode 100644 index 0000000000..45696d4985 --- /dev/null +++ b/Content.Server/Bed/BedSystem.cs @@ -0,0 +1,115 @@ +using Content.Shared.Damage; +using Content.Server.Bed.Components; +using Content.Server.Buckle.Components; +using Content.Server.Body.Systems; +using Content.Shared.Buckle.Components; +using Content.Shared.Body.Components; +using Content.Shared.Bed; +using Content.Server.Power.Components; +using Content.Shared.Emag.Systems; + +namespace Content.Server.Bed +{ + public sealed class BedSystem : EntitySystem + { + [Dependency] private readonly DamageableSystem _damageableSystem = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(ManageUpdateList); + SubscribeLocalEvent(OnBuckleChange); + SubscribeLocalEvent(OnPowerChanged); + SubscribeLocalEvent(OnEmagged); + } + + private void ManageUpdateList(EntityUid uid, HealOnBuckleComponent component, BuckleChangeEvent args) + { + if (args.Buckling) + { + AddComp(uid); + return; + } + + RemComp(uid); + component.Accumulator = 0; + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + foreach (var healingComp in EntityQuery(true)) + { + var bed = healingComp.Owner; + var bedComponent = EntityManager.GetComponent(bed); + var strapComponent = EntityManager.GetComponent(bed); + + bedComponent.Accumulator += frameTime; + + if (bedComponent.Accumulator < bedComponent.HealTime) + { + continue; + } + bedComponent.Accumulator -= bedComponent.HealTime; + foreach (EntityUid healedEntity in strapComponent.BuckledEntities) + { + _damageableSystem.TryChangeDamage(healedEntity, bedComponent.Damage, true); + } + } + } + + private void UpdateAppearance(EntityUid uid, bool isOn) + { + if (!TryComp(uid, out var appearance)) + return; + + appearance.SetData(StasisBedVisuals.IsOn, isOn); + } + + private void OnBuckleChange(EntityUid uid, StasisBedComponent component, BuckleChangeEvent args) + { + // In testing this also received an unbuckle event when the bed is destroyed + // So don't worry about that + if (!TryComp(args.BuckledEntity, out var body)) + return; + + if (TryComp(uid, out var power) && !power.Powered) + return; + + var metabolicEvent = new ApplyMetabolicMultiplierEvent() + {Uid = args.BuckledEntity, Multiplier = component.Multiplier, Apply = args.Buckling}; + RaiseLocalEvent(args.BuckledEntity, metabolicEvent, false); + } + + private void OnPowerChanged(EntityUid uid, StasisBedComponent component, PowerChangedEvent args) + { + UpdateAppearance(uid, args.Powered); + UpdateMetabolisms(uid, component, args.Powered); + } + + private void OnEmagged(EntityUid uid, StasisBedComponent component, GotEmaggedEvent args) + { + ///Repeatable + ///Reset any metabolisms first so they receive the multiplier correctly + UpdateMetabolisms(uid, component, false); + component.Multiplier = 1 / component.Multiplier; + UpdateMetabolisms(uid, component, true); + args.Handled = true; + } + + private void UpdateMetabolisms(EntityUid uid, StasisBedComponent component, bool shouldApply) + { + if (!TryComp(uid, out var strap) || strap.BuckledEntities.Count == 0) + return; + + foreach (var buckledEntity in strap.BuckledEntities) + { + var metabolicEvent = new ApplyMetabolicMultiplierEvent() + {Uid = buckledEntity, Multiplier = component.Multiplier, Apply = shouldApply}; + RaiseLocalEvent(buckledEntity, metabolicEvent, false); + } + } + } +} + diff --git a/Content.Server/Bed/Components/HealOnBuckle.cs b/Content.Server/Bed/Components/HealOnBuckle.cs new file mode 100644 index 0000000000..51428690aa --- /dev/null +++ b/Content.Server/Bed/Components/HealOnBuckle.cs @@ -0,0 +1,17 @@ +using Content.Shared.Damage; + +namespace Content.Server.Bed.Components +{ + [RegisterComponent] + public sealed class HealOnBuckleComponent : Component + { + [DataField("damage", required: true)] + [ViewVariables(VVAccess.ReadWrite)] + public DamageSpecifier Damage = default!; + + [DataField("healTime", required: false)] + [ViewVariables(VVAccess.ReadWrite)] + public float HealTime = 1f; // How often the bed applies the damage + public float Accumulator = 0f; //Time accumulated + } +} diff --git a/Content.Server/Bed/Components/HealOnBuckleHealing.cs b/Content.Server/Bed/Components/HealOnBuckleHealing.cs new file mode 100644 index 0000000000..d897c140aa --- /dev/null +++ b/Content.Server/Bed/Components/HealOnBuckleHealing.cs @@ -0,0 +1,8 @@ +using Content.Shared.Damage; + +namespace Content.Server.Bed.Components +{ + [RegisterComponent] + public sealed class HealOnBuckleHealingComponent : Component + {} +} diff --git a/Content.Server/Bed/Components/StasisBedComponent.cs b/Content.Server/Bed/Components/StasisBedComponent.cs new file mode 100644 index 0000000000..c0bd7a9b9a --- /dev/null +++ b/Content.Server/Bed/Components/StasisBedComponent.cs @@ -0,0 +1,13 @@ +namespace Content.Server.Bed.Components +{ + [RegisterComponent] + public sealed class StasisBedComponent : Component + { + /// + /// What the metabolic update rate will be multiplied by (higher = slower metabolism) + /// + [DataField("multiplier", required: true)] + [ViewVariables(VVAccess.ReadWrite)] + public float Multiplier = 10f; + } +} diff --git a/Content.Server/Body/Systems/BloodstreamSystem.cs b/Content.Server/Body/Systems/BloodstreamSystem.cs index f4d82118fa..db6c4c1bbc 100644 --- a/Content.Server/Body/Systems/BloodstreamSystem.cs +++ b/Content.Server/Body/Systems/BloodstreamSystem.cs @@ -39,6 +39,7 @@ public sealed class BloodstreamSystem : EntitySystem SubscribeLocalEvent(OnDamageChanged); SubscribeLocalEvent(OnHealthBeingExamined); SubscribeLocalEvent(OnBeingGibbed); + SubscribeLocalEvent(OnApplyMetabolicMultiplier); SubscribeLocalEvent(OnReactionAttempt); } @@ -193,6 +194,19 @@ public sealed class BloodstreamSystem : EntitySystem SpillAllSolutions(uid, component); } + private void OnApplyMetabolicMultiplier(EntityUid uid, BloodstreamComponent component, ApplyMetabolicMultiplierEvent args) + { + if (args.Apply) + { + component.UpdateInterval *= args.Multiplier; + return; + } + component.UpdateInterval /= args.Multiplier; + // Reset the accumulator properly + if (component.AccumulatedFrametime >= component.UpdateInterval) + component.AccumulatedFrametime = component.UpdateInterval; + } + /// /// Attempt to transfer provided solution to internal solution. /// diff --git a/Content.Server/Body/Systems/BodySystem.cs b/Content.Server/Body/Systems/BodySystem.cs index f7635157d7..f81ce01fb3 100644 --- a/Content.Server/Body/Systems/BodySystem.cs +++ b/Content.Server/Body/Systems/BodySystem.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Server.Body.Components; @@ -7,8 +6,6 @@ using Content.Server.Mind.Components; using Content.Shared.Body.Components; using Content.Shared.MobState.Components; using Content.Shared.Movement.EntitySystems; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; using Robust.Shared.Timing; namespace Content.Server.Body.Systems @@ -22,6 +19,7 @@ namespace Content.Server.Body.Systems { base.Initialize(); SubscribeLocalEvent(OnRelayMoveInput); + SubscribeLocalEvent(OnApplyMetabolicMultiplier); } private void OnRelayMoveInput(EntityUid uid, BodyComponent component, RelayMoveInputEvent args) @@ -40,6 +38,15 @@ namespace Content.Server.Body.Systems } } + private void OnApplyMetabolicMultiplier(EntityUid uid, BodyComponent component, ApplyMetabolicMultiplierEvent args) + { + foreach (var (part, _) in component.Parts) + foreach (var mechanism in part.Mechanisms) + { + RaiseLocalEvent(mechanism.Owner, args, false); + } + } + /// /// Returns a list of ValueTuples of and MechanismComponent on each mechanism /// in the given body. diff --git a/Content.Server/Body/Systems/MetabolizerSystem.cs b/Content.Server/Body/Systems/MetabolizerSystem.cs index 73b25951e7..23a63b8fac 100644 --- a/Content.Server/Body/Systems/MetabolizerSystem.cs +++ b/Content.Server/Body/Systems/MetabolizerSystem.cs @@ -2,6 +2,7 @@ using System.Linq; using Content.Server.Body.Components; using Content.Server.Chemistry.Components.SolutionManager; using Content.Server.Chemistry.EntitySystems; +using Content.Server.Bed; using Content.Shared.Administration.Logs; using Content.Shared.Body.Components; using Content.Shared.Chemistry.Components; @@ -10,8 +11,6 @@ using Content.Shared.Database; using Content.Shared.FixedPoint; using Content.Shared.MobState.Components; using JetBrains.Annotations; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; using Robust.Shared.Prototypes; using Robust.Shared.Random; @@ -30,6 +29,7 @@ namespace Content.Server.Body.Systems base.Initialize(); SubscribeLocalEvent(OnMetabolizerInit); + SubscribeLocalEvent(OnApplyMetabolicMultiplier); } private void OnMetabolizerInit(EntityUid uid, MetabolizerComponent component, ComponentInit args) @@ -50,6 +50,18 @@ namespace Content.Server.Body.Systems } } + private void OnApplyMetabolicMultiplier(EntityUid uid, MetabolizerComponent component, ApplyMetabolicMultiplierEvent args) + { + if (args.Apply) + { + component.UpdateFrequency *= args.Multiplier; + return; + } + component.UpdateFrequency /= args.Multiplier; + // Reset the accumulator properly + if (component.AccumulatedFrametime >= component.UpdateFrequency) + component.AccumulatedFrametime = component.UpdateFrequency; + } public override void Update(float frameTime) { base.Update(frameTime); @@ -185,4 +197,13 @@ namespace Content.Server.Body.Systems } } } + public sealed class ApplyMetabolicMultiplierEvent : EntityEventArgs + { + // The entity whose metabolism is being modified + public EntityUid Uid; + // What the metabolism's update rate will be multiplied by + public float Multiplier; + // Apply this multiplier or ignore / reset it? + public bool Apply; + } } diff --git a/Content.Server/Body/Systems/RespiratorSystem.cs b/Content.Server/Body/Systems/RespiratorSystem.cs index 17e52c7b36..f5d1366c47 100644 --- a/Content.Server/Body/Systems/RespiratorSystem.cs +++ b/Content.Server/Body/Systems/RespiratorSystem.cs @@ -38,6 +38,7 @@ namespace Content.Server.Body.Systems // We want to process lung reagents before we inhale new reagents. UpdatesAfter.Add(typeof(MetabolizerSystem)); + SubscribeLocalEvent(OnApplyMetabolicMultiplier); } public override void Update(float frameTime) @@ -93,7 +94,6 @@ namespace Content.Server.Body.Systems respirator.SuffocationCycles = 0; } } - public void Inhale(EntityUid uid, SharedBodyComponent? body=null) { if (!Resolve(uid, ref body, false)) @@ -189,6 +189,26 @@ namespace Content.Server.Body.Systems respirator.Saturation = Math.Clamp(respirator.Saturation, respirator.MinSaturation, respirator.MaxSaturation); } + + private void OnApplyMetabolicMultiplier(EntityUid uid, RespiratorComponent component, ApplyMetabolicMultiplierEvent args) + { + if (args.Apply) + { + component.CycleDelay *= args.Multiplier; + component.Saturation *= args.Multiplier; + component.MaxSaturation *= args.Multiplier; + component.MinSaturation *= args.Multiplier; + return; + } + // This way we don't have to worry about it breaking if the stasis bed component is destroyed + component.CycleDelay /= args.Multiplier; + component.Saturation /= args.Multiplier; + component.MaxSaturation /= args.Multiplier; + component.MinSaturation /= args.Multiplier; + // Reset the accumulator properly + if (component.AccumulatedFrametime >= component.CycleDelay) + component.AccumulatedFrametime = component.CycleDelay; + } } } diff --git a/Content.Server/Body/Systems/StomachSystem.cs b/Content.Server/Body/Systems/StomachSystem.cs index 62b5f8e0fd..8bf64e0e75 100644 --- a/Content.Server/Body/Systems/StomachSystem.cs +++ b/Content.Server/Body/Systems/StomachSystem.cs @@ -1,10 +1,9 @@ using Content.Server.Body.Components; +using Content.Server.Bed; using Content.Server.Chemistry.Components.SolutionManager; using Content.Server.Chemistry.EntitySystems; using Content.Shared.Body.Components; using Content.Shared.Chemistry.Components; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; using Robust.Shared.Utility; namespace Content.Server.Body.Systems @@ -18,6 +17,7 @@ namespace Content.Server.Body.Systems public override void Initialize() { SubscribeLocalEvent(OnComponentInit); + SubscribeLocalEvent(OnApplyMetabolicMultiplier); } public override void Update(float frameTime) @@ -76,6 +76,20 @@ namespace Content.Server.Body.Systems } } + private void OnApplyMetabolicMultiplier(EntityUid uid, StomachComponent component, ApplyMetabolicMultiplierEvent args) + { + if (args.Apply) + { + component.UpdateInterval *= args.Multiplier; + return; + } + // This way we don't have to worry about it breaking if the stasis bed component is destroyed + component.UpdateInterval /= args.Multiplier; + // Reset the accumulator properly + if (component.AccumulatedFrameTime >= component.UpdateInterval) + component.AccumulatedFrameTime = component.UpdateInterval; + } + private void OnComponentInit(EntityUid uid, StomachComponent component, ComponentInit args) { var solution = _solutionContainerSystem.EnsureSolution(uid, DefaultSolutionName); diff --git a/Content.Server/Buckle/Components/BuckleComponent.cs b/Content.Server/Buckle/Components/BuckleComponent.cs index a250d227c0..83593a037c 100644 --- a/Content.Server/Buckle/Components/BuckleComponent.cs +++ b/Content.Server/Buckle/Components/BuckleComponent.cs @@ -232,8 +232,9 @@ namespace Content.Server.Buckle.Components UpdateBuckleStatus(); - var ev = new BuckleChangeEvent() { Buckling = true, Strap = BuckledTo.Owner }; - _entMan.EventBus.RaiseLocalEvent(Owner, ev, false); + var ev = new BuckleChangeEvent() { Buckling = true, Strap = BuckledTo.Owner, BuckledEntity = Owner }; + _entMan.EventBus.RaiseLocalEvent(ev.BuckledEntity, ev, false); + _entMan.EventBus.RaiseLocalEvent(ev.Strap, ev, false); if (_entMan.TryGetComponent(Owner, out SharedPullableComponent? ownerPullable)) { @@ -324,8 +325,9 @@ namespace Content.Server.Buckle.Components oldBuckledTo.Remove(this); SoundSystem.Play(Filter.Pvs(Owner), oldBuckledTo.UnbuckleSound.GetSound(), Owner); - var ev = new BuckleChangeEvent() { Buckling = false, Strap = oldBuckledTo.Owner }; + var ev = new BuckleChangeEvent() { Buckling = false, Strap = oldBuckledTo.Owner, BuckledEntity = Owner }; _entMan.EventBus.RaiseLocalEvent(Owner, ev, false); + _entMan.EventBus.RaiseLocalEvent(oldBuckledTo.Owner, ev, false); return true; } diff --git a/Content.Server/Disease/Cures/DiseaseBedrestCure.cs b/Content.Server/Disease/Cures/DiseaseBedrestCure.cs index 3f90385204..0c60307dc8 100644 --- a/Content.Server/Disease/Cures/DiseaseBedrestCure.cs +++ b/Content.Server/Disease/Cures/DiseaseBedrestCure.cs @@ -1,5 +1,6 @@ using Content.Shared.Disease; using Content.Server.Buckle.Components; +using Content.Server.Bed.Components; namespace Content.Server.Disease.Cures { @@ -7,7 +8,6 @@ namespace Content.Server.Disease.Cures /// Cures the disease after a certain amount of time /// strapped. /// - /// TODO: Revisit after bed pr merged public sealed class DiseaseBedrestCure : DiseaseCure { [ViewVariables(VVAccess.ReadWrite)] @@ -18,7 +18,8 @@ namespace Content.Server.Disease.Cures public override bool Cure(DiseaseEffectArgs args) { - if (!args.EntityManager.TryGetComponent(args.DiseasedEntity, out var buckle)) + if (!args.EntityManager.TryGetComponent(args.DiseasedEntity, out var buckle) || + !args.EntityManager.HasComponent(buckle.BuckledTo?.Owner)) return false; if (buckle.Buckled) Ticker++; diff --git a/Content.Server/Disease/DiseaseSystem.cs b/Content.Server/Disease/DiseaseSystem.cs index c217541bb6..3d29338bad 100644 --- a/Content.Server/Disease/DiseaseSystem.cs +++ b/Content.Server/Disease/DiseaseSystem.cs @@ -4,6 +4,7 @@ using Content.Shared.Disease; using Content.Shared.Disease.Components; using Content.Server.Disease.Components; using Content.Server.Clothing.Components; +using Content.Server.Body.Systems; using Content.Shared.MobState.Components; using Content.Shared.Examine; using Content.Shared.Inventory; @@ -47,6 +48,8 @@ namespace Content.Server.Disease SubscribeLocalEvent(OnUnequipped); SubscribeLocalEvent(OnAfterInteract); SubscribeLocalEvent(OnExamined); + // Handling stuff from other systems + SubscribeLocalEvent(OnApplyMetabolicMultiplier); // Private events stuff SubscribeLocalEvent(OnTargetVaxxSuccessful); SubscribeLocalEvent(OnVaxxCancelled); @@ -285,6 +288,26 @@ namespace Content.Server.Disease } } + + private void OnApplyMetabolicMultiplier(EntityUid uid, DiseaseCarrierComponent component, ApplyMetabolicMultiplierEvent args) + { + if (args.Apply) + { + foreach (var disease in component.Diseases) + { + disease.TickTime *= args.Multiplier; + return; + } + } + foreach (var disease in component.Diseases) + { + disease.TickTime /= args.Multiplier; + if (disease.Accumulator >= disease.TickTime) + disease.Accumulator = disease.TickTime; + } + } + + /// /// Helper functions /// diff --git a/Content.Server/Entry/IgnoredComponents.cs b/Content.Server/Entry/IgnoredComponents.cs index c178a373fb..e3748402fb 100644 --- a/Content.Server/Entry/IgnoredComponents.cs +++ b/Content.Server/Entry/IgnoredComponents.cs @@ -7,6 +7,7 @@ namespace Content.Server.Entry "ConstructionGhost", "IconSmooth", "ReinforcedWall", + "StasisBedVisuals", "InteractionOutline", "MeleeWeaponArcAnimation", "AnimationsTest", diff --git a/Content.Shared/Bed/StasisBedVisuals.cs b/Content.Shared/Bed/StasisBedVisuals.cs new file mode 100644 index 0000000000..cf7bc06460 --- /dev/null +++ b/Content.Shared/Bed/StasisBedVisuals.cs @@ -0,0 +1,10 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.Bed +{ + [Serializable, NetSerializable] + public enum StasisBedVisuals : byte + { + IsOn, + } +} diff --git a/Content.Shared/Buckle/Components/SharedBuckleComponent.cs b/Content.Shared/Buckle/Components/SharedBuckleComponent.cs index ac6a605c89..b2b6521b92 100644 --- a/Content.Shared/Buckle/Components/SharedBuckleComponent.cs +++ b/Content.Shared/Buckle/Components/SharedBuckleComponent.cs @@ -62,6 +62,8 @@ namespace Content.Shared.Buckle.Components public sealed class BuckleChangeEvent : EntityEventArgs { public EntityUid Strap; + + public EntityUid BuckledEntity; public bool Buckling; } diff --git a/Content.Shared/Disease/DiseasePrototype.cs b/Content.Shared/Disease/DiseasePrototype.cs index b6bdff519d..c846f56343 100644 --- a/Content.Shared/Disease/DiseasePrototype.cs +++ b/Content.Shared/Disease/DiseasePrototype.cs @@ -28,6 +28,7 @@ namespace Content.Shared.Disease /// /// Controls how often a disease ticks. /// + [ViewVariables] public float TickTime = 1f; /// diff --git a/Resources/Prototypes/Catalog/Research/technologies.yml b/Resources/Prototypes/Catalog/Research/technologies.yml index 15657e8758..83d7a601db 100644 --- a/Resources/Prototypes/Catalog/Research/technologies.yml +++ b/Resources/Prototypes/Catalog/Research/technologies.yml @@ -104,17 +104,15 @@ - type: technology name: "medical machinery" id: MedicalMachinery - description: More machine power for more healing efficiency. + description: Machines any self-respecting medbay would need. icon: - sprite: Structures/Machines/cloning.rsi - state: pod_0 - requiredPoints: 15000 + sprite: Structures/dispensers.rsi + state: industrial-working + requiredPoints: 10000 requiredTechnologies: - BiologicalTechnology - ChemistryTechnology unlockedRecipes: - - CloningPodMachineCircuitboard - - MedicalScannerMachineCircuitboard - ChemMasterMachineCircuitboard - ChemDispenserMachineCircuitboard - CrewMonitoringComputerCircuitboard @@ -122,6 +120,22 @@ - DiagnoserMachineCircuitboard - HandheldCrewMonitor +- type: technology + name: "advanced life support systems" + id: AdvancedLifeSupport + description: The cutting edge of life and death. + icon: + sprite: Structures/Machines/cloning.rsi + state: pod_0 + requiredPoints: 20000 + requiredTechnologies: + - MedicalMachinery + - AdvancedSugery + unlockedRecipes: + - CloningPodMachineCircuitboard + - MedicalScannerMachineCircuitboard + - StasisBedMachineCircuitboard + # Security Technology Tree - type: technology @@ -328,7 +342,7 @@ - SolarControlComputerCircuitboard - GeneratorPlasmaMachineCircuitboard - GeneratorUraniumMachineCircuitboard - + - type: technology name: "compact power technology" id: CompactPowerTechnology diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml index 19ec78aeaf..ca8df9ce05 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml @@ -312,3 +312,26 @@ Amount: 1 DefaultPrototype: Beaker ExamineName: Glass Beaker + +- type: entity + id: StasisBedMachineCircuitboard + parent: BaseMachineCircuitboard + name: Stasis Bed (Machine Board) + components: + - type: MachineBoard + prototype: StasisBed + requirements: + Capacitor: 1 + Manipulator: 1 + materialRequirements: + Cable: 3 + tagRequirements: + Pipe: + Amount: 4 + DefaultPrototype: GasPipeStraight + ExamineName: Pipe + Cryobeaker: + Amount: 2 + DefaultPrototype: CryostasisBeaker + ExamineName: Cryostasis Beaker + diff --git a/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml b/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml index 34b15e4fb0..4a4cb1b296 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml @@ -144,7 +144,11 @@ solution: beaker - !type:DoActsBehavior acts: [ "Destruction" ] - + - type: Tag + tags: + - GlassBeaker + - Cryobeaker + - type: entity name: bluespace beaker parent: BaseBeaker diff --git a/Resources/Prototypes/Entities/Structures/Furniture/beds.yml b/Resources/Prototypes/Entities/Structures/Furniture/beds.yml index 262651e540..f0ac36fb03 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/beds.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/beds.yml @@ -2,8 +2,15 @@ name: bed id: Bed parent: BaseStructure - description: This is used to lie in, sleep in or strap on. + description: This is used to lie in, sleep in or strap on. Resting here provides extremely slow healing. components: + - type: HealOnBuckle + damage: + groups: + Brute: -0.2 ## 0.1 per + Burn: -0.2 + types: + Poison: -0.1 - type: Physics bodyType: Static - type: Fixtures @@ -52,6 +59,25 @@ - type: Pullable +- type: entity + parent: Bed + id: MedicalBed + name: medical bed + description: A hospital bed for patients to recover in. Resting here provides fairly slow healing. + components: + - type: Sprite + state: bed-MED + - type: HealOnBuckle + damage: + groups: + Brute: -0.4 ## 0.2 per + Burn: -0.4 + types: + Poison: -0.2 + - type: Construction + graph: bed + node: medicalbed + - type: entity parent: Bed id: DogBed diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index e3ae8f53f7..94a3ed64b0 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -245,6 +245,7 @@ - ShuttleConsoleCircuitboard - CircuitImprinterMachineCircuitboard - DawInstrumentMachineCircuitboard + - StasisBedMachineCircuitboard - type: Machine board: CircuitImprinterMachineCircuitboard diff --git a/Resources/Prototypes/Entities/Structures/Machines/stasisbed.yml b/Resources/Prototypes/Entities/Structures/Machines/stasisbed.yml new file mode 100644 index 0000000000..5f0989f1ee --- /dev/null +++ b/Resources/Prototypes/Entities/Structures/Machines/stasisbed.yml @@ -0,0 +1,51 @@ +- type: entity + id: StasisBed + name: stasis bed + parent: BaseStructure + description: A bed that massively slows down the patient's metabolism, allowing more time to administer a proper treatment for stabilization. + components: + - type: StasisBed + multiplier: 10 + - type: Sprite + sprite: Structures/Machines/stasis_bed.rsi + netsync: false + layers: + - state: icon + - state: unlit + shader: unshaded + map: ["enum.StasisBedVisualLayers.IsOn"] + - type: StasisBedVisuals + - type: Appearance + - type: ApcPowerReceiver + powerLoad: 1000 + - type: ExtensionCableReceiver + - type: Damageable + damageContainer: Inorganic + damageModifierSet: Metallic + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 75 + behaviors: + - !type:DoActsBehavior + acts: ["Destruction"] + - !type:SpawnEntitiesBehavior + spawn: + SheetSteel1: + min: 1 + max: 2 + - type: Strap + position: Down + rotation: -90 + - type: Physics + bodyType: Static + - type: Fixtures + fixtures: + - shape: + !type:PhysShapeAabb + bounds: "-0.45,-0.45,0.45,0.05" + mass: 25 + mask: + - SmallImpassable + diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/furniture/bed.yml b/Resources/Prototypes/Recipes/Construction/Graphs/furniture/bed.yml index fbeb329c7b..aef6ae702f 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/furniture/bed.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/furniture/bed.yml @@ -20,6 +20,13 @@ - material: WoodPlank amount: 10 doAfter: 1 + - to: medicalbed + completed: + - !type:SnapToGrid { } + steps: + - material: Plasteel + amount: 2 + doAfter: 1 - node: bed entity: Bed edges: @@ -42,3 +49,14 @@ steps: - tool: Screwing doAfter: 1 + - node: medicalbed + entity: MedicalBed + edges: + - to: start + completed: + - !type:SpawnPrototype + prototype: SheetPlasteel1 + amount: 2 + steps: + - tool: Screwing + doAfter: 1 diff --git a/Resources/Prototypes/Recipes/Construction/furniture.yml b/Resources/Prototypes/Recipes/Construction/furniture.yml index f9fd51ce4e..a2d91da64f 100644 --- a/Resources/Prototypes/Recipes/Construction/furniture.yml +++ b/Resources/Prototypes/Recipes/Construction/furniture.yml @@ -100,7 +100,7 @@ canBuildInImpassable: false conditions: - !type:TileNotBlocked - + - type: construction name: pilots chair id: chairPilotSeat @@ -294,7 +294,7 @@ - type: construction id: Bed name: bed - description: This is used to lie in, sleep in or strap on. + description: This is used to lie in, sleep in or strap on. Resting here provides extremely slow healing. graph: bed startNode: start targetNode: bed @@ -308,6 +308,23 @@ conditions: - !type:TileNotBlocked +- type: construction + id: MedicalBed + name: Medical Bed + description: A hospital bed for patients to recover in. Resting here provides fairly slow healing. + graph: bed + startNode: start + targetNode: medicalbed + category: Furniture + icon: + sprite: Structures/Furniture/furniture.rsi + state: bed-MED + objectType: Structure + placementMode: SnapgridCenter + canBuildInImpassable: false + conditions: + - !type:TileNotBlocked + - type: construction id: DogBed name: dog bed diff --git a/Resources/Prototypes/Recipes/Lathes/electronics.yml b/Resources/Prototypes/Recipes/Lathes/electronics.yml index 6931efb895..f044b04760 100644 --- a/Resources/Prototypes/Recipes/Lathes/electronics.yml +++ b/Resources/Prototypes/Recipes/Lathes/electronics.yml @@ -185,6 +185,15 @@ Steel: 100 Glass: 900 +- type: latheRecipe + id: StasisBedMachineCircuitboard + icon: Objects/Misc/module.rsi/id_mod.png + result: StasisBedMachineCircuitboard + completetime: 1000 + materials: + Steel: 100 + Glass: 900 + Gold: 100 # Power - type: latheRecipe id: APCElectronics @@ -203,7 +212,7 @@ materials: Steel: 50 Glass: 450 - + - type: latheRecipe id: WallmountSubstationElectronics icon: Objects/Misc/module.rsi/id_mod.png @@ -221,7 +230,7 @@ materials: Steel: 100 Glass: 900 - + - type: latheRecipe id: GeneratorPlasmaMachineCircuitboard icon: Objects/Misc/module.rsi/id_mod.png @@ -230,7 +239,7 @@ materials: Steel: 50 Glass: 350 - + - type: latheRecipe id: GeneratorUraniumMachineCircuitboard icon: Objects/Misc/module.rsi/id_mod.png @@ -239,7 +248,7 @@ materials: Steel: 50 Glass: 350 - + - type: latheRecipe id: WallmountGeneratorElectronics icon: Objects/Misc/module.rsi/id_mod.png @@ -248,7 +257,7 @@ materials: Steel: 50 Glass: 350 - + - type: latheRecipe id: WallmountGeneratorAPUElectronics icon: Objects/Misc/module.rsi/id_mod.png @@ -257,7 +266,7 @@ materials: Steel: 50 Glass: 350 - + - type: latheRecipe id: SolarControlComputerCircuitboard icon: Objects/Misc/module.rsi/id_mod.png diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index 75c37ff665..af86152f82 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -90,6 +90,9 @@ - type: Tag id: CrowbarRed +- type: Tag + id: Cryobeaker + - type: Tag id: ConveyorAssembly @@ -221,7 +224,7 @@ - type: Tag id: Payload # for grenade/bomb crafting - + - type: Tag id: PercussionInstrument diff --git a/Resources/Textures/Structures/Furniture/furniture.rsi/bed-MED.png b/Resources/Textures/Structures/Furniture/furniture.rsi/bed-MED.png new file mode 100644 index 0000000000..a2fd75e323 Binary files /dev/null and b/Resources/Textures/Structures/Furniture/furniture.rsi/bed-MED.png differ diff --git a/Resources/Textures/Structures/Furniture/furniture.rsi/meta.json b/Resources/Textures/Structures/Furniture/furniture.rsi/meta.json index 637386e12b..f929c9dffc 100644 --- a/Resources/Textures/Structures/Furniture/furniture.rsi/meta.json +++ b/Resources/Textures/Structures/Furniture/furniture.rsi/meta.json @@ -10,6 +10,9 @@ { "name": "bed" }, + { + "name": "bed-MED" + }, { "name": "dogbed" }, diff --git a/Resources/Textures/Structures/Machines/stasis_bed.rsi/broken.png b/Resources/Textures/Structures/Machines/stasis_bed.rsi/broken.png new file mode 100644 index 0000000000..8aa326df3e Binary files /dev/null and b/Resources/Textures/Structures/Machines/stasis_bed.rsi/broken.png differ diff --git a/Resources/Textures/Structures/Machines/stasis_bed.rsi/icon.png b/Resources/Textures/Structures/Machines/stasis_bed.rsi/icon.png new file mode 100644 index 0000000000..aeb8476c8e Binary files /dev/null and b/Resources/Textures/Structures/Machines/stasis_bed.rsi/icon.png differ diff --git a/Resources/Textures/Structures/Machines/stasis_bed.rsi/meta.json b/Resources/Textures/Structures/Machines/stasis_bed.rsi/meta.json new file mode 100644 index 0000000000..ad9670cd5b --- /dev/null +++ b/Resources/Textures/Structures/Machines/stasis_bed.rsi/meta.json @@ -0,0 +1,36 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/40d89d11ea4a5cb81d61dc1018b46f4e7d32c62a", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "broken", + "delays": [ + [ + 1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "panel", + "directions": 4 + }, + { + "name": "unlit", + "directions": 4 + }, + { + "name": "icon", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Structures/Machines/stasis_bed.rsi/panel.png b/Resources/Textures/Structures/Machines/stasis_bed.rsi/panel.png new file mode 100644 index 0000000000..93eb0cd498 Binary files /dev/null and b/Resources/Textures/Structures/Machines/stasis_bed.rsi/panel.png differ diff --git a/Resources/Textures/Structures/Machines/stasis_bed.rsi/unlit.png b/Resources/Textures/Structures/Machines/stasis_bed.rsi/unlit.png new file mode 100644 index 0000000000..be56a5ed72 Binary files /dev/null and b/Resources/Textures/Structures/Machines/stasis_bed.rsi/unlit.png differ