Beds, Medical Beds, Stasis Beds (#6695)

This commit is contained in:
Rane
2022-04-15 18:53:52 -04:00
committed by GitHub
parent 3383350c03
commit 5376aed6ea
36 changed files with 534 additions and 31 deletions

View File

@@ -0,0 +1,5 @@
namespace Content.Client.Bed;
[RegisterComponent]
public sealed class StasisBedVisualsComponent : Component
{}

View File

@@ -0,0 +1,22 @@
using Content.Shared.Bed;
using Robust.Client.GameObjects;
namespace Content.Client.Bed
{
public sealed class StasisBedSystem : VisualizerSystem<StasisBedVisualsComponent>
{
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,
}
}

View File

@@ -272,6 +272,8 @@ namespace Content.Client.Entry
"BeingCloned", "BeingCloned",
"Advertise", "Advertise",
"Bible", "Bible",
"HealOnBuckle",
"StasisBed",
"PowerNetworkBattery", "PowerNetworkBattery",
"BatteryCharger", "BatteryCharger",
"UnpoweredFlashlight", "UnpoweredFlashlight",

View File

@@ -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<HealOnBuckleComponent, BuckleChangeEvent>(ManageUpdateList);
SubscribeLocalEvent<StasisBedComponent, BuckleChangeEvent>(OnBuckleChange);
SubscribeLocalEvent<StasisBedComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<StasisBedComponent, GotEmaggedEvent>(OnEmagged);
}
private void ManageUpdateList(EntityUid uid, HealOnBuckleComponent component, BuckleChangeEvent args)
{
if (args.Buckling)
{
AddComp<HealOnBuckleHealingComponent>(uid);
return;
}
RemComp<HealOnBuckleHealingComponent>(uid);
component.Accumulator = 0;
}
public override void Update(float frameTime)
{
base.Update(frameTime);
foreach (var healingComp in EntityQuery<HealOnBuckleHealingComponent>(true))
{
var bed = healingComp.Owner;
var bedComponent = EntityManager.GetComponent<HealOnBuckleComponent>(bed);
var strapComponent = EntityManager.GetComponent<StrapComponent>(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<AppearanceComponent>(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<SharedBodyComponent>(args.BuckledEntity, out var body))
return;
if (TryComp<ApcPowerReceiverComponent>(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<StrapComponent>(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);
}
}
}
}

View File

@@ -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
}
}

View File

@@ -0,0 +1,8 @@
using Content.Shared.Damage;
namespace Content.Server.Bed.Components
{
[RegisterComponent]
public sealed class HealOnBuckleHealingComponent : Component
{}
}

View File

@@ -0,0 +1,13 @@
namespace Content.Server.Bed.Components
{
[RegisterComponent]
public sealed class StasisBedComponent : Component
{
/// <summary>
/// What the metabolic update rate will be multiplied by (higher = slower metabolism)
/// </summary>
[DataField("multiplier", required: true)]
[ViewVariables(VVAccess.ReadWrite)]
public float Multiplier = 10f;
}
}

View File

@@ -39,6 +39,7 @@ public sealed class BloodstreamSystem : EntitySystem
SubscribeLocalEvent<BloodstreamComponent, DamageChangedEvent>(OnDamageChanged); SubscribeLocalEvent<BloodstreamComponent, DamageChangedEvent>(OnDamageChanged);
SubscribeLocalEvent<BloodstreamComponent, HealthBeingExaminedEvent>(OnHealthBeingExamined); SubscribeLocalEvent<BloodstreamComponent, HealthBeingExaminedEvent>(OnHealthBeingExamined);
SubscribeLocalEvent<BloodstreamComponent, BeingGibbedEvent>(OnBeingGibbed); SubscribeLocalEvent<BloodstreamComponent, BeingGibbedEvent>(OnBeingGibbed);
SubscribeLocalEvent<BloodstreamComponent, ApplyMetabolicMultiplierEvent>(OnApplyMetabolicMultiplier);
SubscribeLocalEvent<BloodstreamComponent, ReactionAttemptEvent>(OnReactionAttempt); SubscribeLocalEvent<BloodstreamComponent, ReactionAttemptEvent>(OnReactionAttempt);
} }
@@ -193,6 +194,19 @@ public sealed class BloodstreamSystem : EntitySystem
SpillAllSolutions(uid, component); 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;
}
/// <summary> /// <summary>
/// Attempt to transfer provided solution to internal solution. /// Attempt to transfer provided solution to internal solution.
/// </summary> /// </summary>

View File

@@ -1,4 +1,3 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using Content.Server.Body.Components; using Content.Server.Body.Components;
@@ -7,8 +6,6 @@ using Content.Server.Mind.Components;
using Content.Shared.Body.Components; using Content.Shared.Body.Components;
using Content.Shared.MobState.Components; using Content.Shared.MobState.Components;
using Content.Shared.Movement.EntitySystems; using Content.Shared.Movement.EntitySystems;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Timing; using Robust.Shared.Timing;
namespace Content.Server.Body.Systems namespace Content.Server.Body.Systems
@@ -22,6 +19,7 @@ namespace Content.Server.Body.Systems
{ {
base.Initialize(); base.Initialize();
SubscribeLocalEvent<BodyComponent, RelayMoveInputEvent>(OnRelayMoveInput); SubscribeLocalEvent<BodyComponent, RelayMoveInputEvent>(OnRelayMoveInput);
SubscribeLocalEvent<BodyComponent, ApplyMetabolicMultiplierEvent>(OnApplyMetabolicMultiplier);
} }
private void OnRelayMoveInput(EntityUid uid, BodyComponent component, RelayMoveInputEvent args) 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);
}
}
/// <summary> /// <summary>
/// Returns a list of ValueTuples of <see cref="T"/> and MechanismComponent on each mechanism /// Returns a list of ValueTuples of <see cref="T"/> and MechanismComponent on each mechanism
/// in the given body. /// in the given body.

View File

@@ -2,6 +2,7 @@ using System.Linq;
using Content.Server.Body.Components; using Content.Server.Body.Components;
using Content.Server.Chemistry.Components.SolutionManager; using Content.Server.Chemistry.Components.SolutionManager;
using Content.Server.Chemistry.EntitySystems; using Content.Server.Chemistry.EntitySystems;
using Content.Server.Bed;
using Content.Shared.Administration.Logs; using Content.Shared.Administration.Logs;
using Content.Shared.Body.Components; using Content.Shared.Body.Components;
using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components;
@@ -10,8 +11,6 @@ using Content.Shared.Database;
using Content.Shared.FixedPoint; using Content.Shared.FixedPoint;
using Content.Shared.MobState.Components; using Content.Shared.MobState.Components;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Random; using Robust.Shared.Random;
@@ -30,6 +29,7 @@ namespace Content.Server.Body.Systems
base.Initialize(); base.Initialize();
SubscribeLocalEvent<MetabolizerComponent, ComponentInit>(OnMetabolizerInit); SubscribeLocalEvent<MetabolizerComponent, ComponentInit>(OnMetabolizerInit);
SubscribeLocalEvent<MetabolizerComponent, ApplyMetabolicMultiplierEvent>(OnApplyMetabolicMultiplier);
} }
private void OnMetabolizerInit(EntityUid uid, MetabolizerComponent component, ComponentInit args) 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) public override void Update(float frameTime)
{ {
base.Update(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;
}
} }

View File

@@ -38,6 +38,7 @@ namespace Content.Server.Body.Systems
// We want to process lung reagents before we inhale new reagents. // We want to process lung reagents before we inhale new reagents.
UpdatesAfter.Add(typeof(MetabolizerSystem)); UpdatesAfter.Add(typeof(MetabolizerSystem));
SubscribeLocalEvent<RespiratorComponent, ApplyMetabolicMultiplierEvent>(OnApplyMetabolicMultiplier);
} }
public override void Update(float frameTime) public override void Update(float frameTime)
@@ -93,7 +94,6 @@ namespace Content.Server.Body.Systems
respirator.SuffocationCycles = 0; respirator.SuffocationCycles = 0;
} }
} }
public void Inhale(EntityUid uid, SharedBodyComponent? body=null) public void Inhale(EntityUid uid, SharedBodyComponent? body=null)
{ {
if (!Resolve(uid, ref body, false)) if (!Resolve(uid, ref body, false))
@@ -189,6 +189,26 @@ namespace Content.Server.Body.Systems
respirator.Saturation = respirator.Saturation =
Math.Clamp(respirator.Saturation, respirator.MinSaturation, respirator.MaxSaturation); 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;
}
} }
} }

View File

@@ -1,10 +1,9 @@
using Content.Server.Body.Components; using Content.Server.Body.Components;
using Content.Server.Bed;
using Content.Server.Chemistry.Components.SolutionManager; using Content.Server.Chemistry.Components.SolutionManager;
using Content.Server.Chemistry.EntitySystems; using Content.Server.Chemistry.EntitySystems;
using Content.Shared.Body.Components; using Content.Shared.Body.Components;
using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Utility; using Robust.Shared.Utility;
namespace Content.Server.Body.Systems namespace Content.Server.Body.Systems
@@ -18,6 +17,7 @@ namespace Content.Server.Body.Systems
public override void Initialize() public override void Initialize()
{ {
SubscribeLocalEvent<StomachComponent, ComponentInit>(OnComponentInit); SubscribeLocalEvent<StomachComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<StomachComponent, ApplyMetabolicMultiplierEvent>(OnApplyMetabolicMultiplier);
} }
public override void Update(float frameTime) 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) private void OnComponentInit(EntityUid uid, StomachComponent component, ComponentInit args)
{ {
var solution = _solutionContainerSystem.EnsureSolution(uid, DefaultSolutionName); var solution = _solutionContainerSystem.EnsureSolution(uid, DefaultSolutionName);

View File

@@ -232,8 +232,9 @@ namespace Content.Server.Buckle.Components
UpdateBuckleStatus(); UpdateBuckleStatus();
var ev = new BuckleChangeEvent() { Buckling = true, Strap = BuckledTo.Owner }; var ev = new BuckleChangeEvent() { Buckling = true, Strap = BuckledTo.Owner, BuckledEntity = Owner };
_entMan.EventBus.RaiseLocalEvent(Owner, ev, false); _entMan.EventBus.RaiseLocalEvent(ev.BuckledEntity, ev, false);
_entMan.EventBus.RaiseLocalEvent(ev.Strap, ev, false);
if (_entMan.TryGetComponent(Owner, out SharedPullableComponent? ownerPullable)) if (_entMan.TryGetComponent(Owner, out SharedPullableComponent? ownerPullable))
{ {
@@ -324,8 +325,9 @@ namespace Content.Server.Buckle.Components
oldBuckledTo.Remove(this); oldBuckledTo.Remove(this);
SoundSystem.Play(Filter.Pvs(Owner), oldBuckledTo.UnbuckleSound.GetSound(), Owner); 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(Owner, ev, false);
_entMan.EventBus.RaiseLocalEvent(oldBuckledTo.Owner, ev, false);
return true; return true;
} }

View File

@@ -1,5 +1,6 @@
using Content.Shared.Disease; using Content.Shared.Disease;
using Content.Server.Buckle.Components; using Content.Server.Buckle.Components;
using Content.Server.Bed.Components;
namespace Content.Server.Disease.Cures namespace Content.Server.Disease.Cures
{ {
@@ -7,7 +8,6 @@ namespace Content.Server.Disease.Cures
/// Cures the disease after a certain amount of time /// Cures the disease after a certain amount of time
/// strapped. /// strapped.
/// </summary> /// </summary>
/// TODO: Revisit after bed pr merged
public sealed class DiseaseBedrestCure : DiseaseCure public sealed class DiseaseBedrestCure : DiseaseCure
{ {
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
@@ -18,7 +18,8 @@ namespace Content.Server.Disease.Cures
public override bool Cure(DiseaseEffectArgs args) public override bool Cure(DiseaseEffectArgs args)
{ {
if (!args.EntityManager.TryGetComponent<BuckleComponent>(args.DiseasedEntity, out var buckle)) if (!args.EntityManager.TryGetComponent<BuckleComponent>(args.DiseasedEntity, out var buckle) ||
!args.EntityManager.HasComponent<HealOnBuckleComponent>(buckle.BuckledTo?.Owner))
return false; return false;
if (buckle.Buckled) if (buckle.Buckled)
Ticker++; Ticker++;

View File

@@ -4,6 +4,7 @@ using Content.Shared.Disease;
using Content.Shared.Disease.Components; using Content.Shared.Disease.Components;
using Content.Server.Disease.Components; using Content.Server.Disease.Components;
using Content.Server.Clothing.Components; using Content.Server.Clothing.Components;
using Content.Server.Body.Systems;
using Content.Shared.MobState.Components; using Content.Shared.MobState.Components;
using Content.Shared.Examine; using Content.Shared.Examine;
using Content.Shared.Inventory; using Content.Shared.Inventory;
@@ -47,6 +48,8 @@ namespace Content.Server.Disease
SubscribeLocalEvent<DiseaseProtectionComponent, GotUnequippedEvent>(OnUnequipped); SubscribeLocalEvent<DiseaseProtectionComponent, GotUnequippedEvent>(OnUnequipped);
SubscribeLocalEvent<DiseaseVaccineComponent, AfterInteractEvent>(OnAfterInteract); SubscribeLocalEvent<DiseaseVaccineComponent, AfterInteractEvent>(OnAfterInteract);
SubscribeLocalEvent<DiseaseVaccineComponent, ExaminedEvent>(OnExamined); SubscribeLocalEvent<DiseaseVaccineComponent, ExaminedEvent>(OnExamined);
// Handling stuff from other systems
SubscribeLocalEvent<DiseaseCarrierComponent, ApplyMetabolicMultiplierEvent>(OnApplyMetabolicMultiplier);
// Private events stuff // Private events stuff
SubscribeLocalEvent<TargetVaxxSuccessfulEvent>(OnTargetVaxxSuccessful); SubscribeLocalEvent<TargetVaxxSuccessfulEvent>(OnTargetVaxxSuccessful);
SubscribeLocalEvent<VaxxCancelledEvent>(OnVaxxCancelled); SubscribeLocalEvent<VaxxCancelledEvent>(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 /// Helper functions
/// ///

View File

@@ -7,6 +7,7 @@ namespace Content.Server.Entry
"ConstructionGhost", "ConstructionGhost",
"IconSmooth", "IconSmooth",
"ReinforcedWall", "ReinforcedWall",
"StasisBedVisuals",
"InteractionOutline", "InteractionOutline",
"MeleeWeaponArcAnimation", "MeleeWeaponArcAnimation",
"AnimationsTest", "AnimationsTest",

View File

@@ -0,0 +1,10 @@
using Robust.Shared.Serialization;
namespace Content.Shared.Bed
{
[Serializable, NetSerializable]
public enum StasisBedVisuals : byte
{
IsOn,
}
}

View File

@@ -62,6 +62,8 @@ namespace Content.Shared.Buckle.Components
public sealed class BuckleChangeEvent : EntityEventArgs public sealed class BuckleChangeEvent : EntityEventArgs
{ {
public EntityUid Strap; public EntityUid Strap;
public EntityUid BuckledEntity;
public bool Buckling; public bool Buckling;
} }

View File

@@ -28,6 +28,7 @@ namespace Content.Shared.Disease
/// <summary> /// <summary>
/// Controls how often a disease ticks. /// Controls how often a disease ticks.
/// </summary> /// </summary>
[ViewVariables]
public float TickTime = 1f; public float TickTime = 1f;
/// <summary> /// <summary>

View File

@@ -104,17 +104,15 @@
- type: technology - type: technology
name: "medical machinery" name: "medical machinery"
id: MedicalMachinery id: MedicalMachinery
description: More machine power for more healing efficiency. description: Machines any self-respecting medbay would need.
icon: icon:
sprite: Structures/Machines/cloning.rsi sprite: Structures/dispensers.rsi
state: pod_0 state: industrial-working
requiredPoints: 15000 requiredPoints: 10000
requiredTechnologies: requiredTechnologies:
- BiologicalTechnology - BiologicalTechnology
- ChemistryTechnology - ChemistryTechnology
unlockedRecipes: unlockedRecipes:
- CloningPodMachineCircuitboard
- MedicalScannerMachineCircuitboard
- ChemMasterMachineCircuitboard - ChemMasterMachineCircuitboard
- ChemDispenserMachineCircuitboard - ChemDispenserMachineCircuitboard
- CrewMonitoringComputerCircuitboard - CrewMonitoringComputerCircuitboard
@@ -122,6 +120,22 @@
- DiagnoserMachineCircuitboard - DiagnoserMachineCircuitboard
- HandheldCrewMonitor - 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 # Security Technology Tree
- type: technology - type: technology

View File

@@ -312,3 +312,26 @@
Amount: 1 Amount: 1
DefaultPrototype: Beaker DefaultPrototype: Beaker
ExamineName: Glass 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

View File

@@ -144,6 +144,10 @@
solution: beaker solution: beaker
- !type:DoActsBehavior - !type:DoActsBehavior
acts: [ "Destruction" ] acts: [ "Destruction" ]
- type: Tag
tags:
- GlassBeaker
- Cryobeaker
- type: entity - type: entity
name: bluespace beaker name: bluespace beaker

View File

@@ -2,8 +2,15 @@
name: bed name: bed
id: Bed id: Bed
parent: BaseStructure 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: components:
- type: HealOnBuckle
damage:
groups:
Brute: -0.2 ## 0.1 per
Burn: -0.2
types:
Poison: -0.1
- type: Physics - type: Physics
bodyType: Static bodyType: Static
- type: Fixtures - type: Fixtures
@@ -52,6 +59,25 @@
- type: Pullable - 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 - type: entity
parent: Bed parent: Bed
id: DogBed id: DogBed

View File

@@ -245,6 +245,7 @@
- ShuttleConsoleCircuitboard - ShuttleConsoleCircuitboard
- CircuitImprinterMachineCircuitboard - CircuitImprinterMachineCircuitboard
- DawInstrumentMachineCircuitboard - DawInstrumentMachineCircuitboard
- StasisBedMachineCircuitboard
- type: Machine - type: Machine
board: CircuitImprinterMachineCircuitboard board: CircuitImprinterMachineCircuitboard

View File

@@ -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

View File

@@ -20,6 +20,13 @@
- material: WoodPlank - material: WoodPlank
amount: 10 amount: 10
doAfter: 1 doAfter: 1
- to: medicalbed
completed:
- !type:SnapToGrid { }
steps:
- material: Plasteel
amount: 2
doAfter: 1
- node: bed - node: bed
entity: Bed entity: Bed
edges: edges:
@@ -42,3 +49,14 @@
steps: steps:
- tool: Screwing - tool: Screwing
doAfter: 1 doAfter: 1
- node: medicalbed
entity: MedicalBed
edges:
- to: start
completed:
- !type:SpawnPrototype
prototype: SheetPlasteel1
amount: 2
steps:
- tool: Screwing
doAfter: 1

View File

@@ -294,7 +294,7 @@
- type: construction - type: construction
id: Bed id: Bed
name: 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 graph: bed
startNode: start startNode: start
targetNode: bed targetNode: bed
@@ -308,6 +308,23 @@
conditions: conditions:
- !type:TileNotBlocked - !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 - type: construction
id: DogBed id: DogBed
name: dog bed name: dog bed

View File

@@ -185,6 +185,15 @@
Steel: 100 Steel: 100
Glass: 900 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 # Power
- type: latheRecipe - type: latheRecipe
id: APCElectronics id: APCElectronics

View File

@@ -90,6 +90,9 @@
- type: Tag - type: Tag
id: CrowbarRed id: CrowbarRed
- type: Tag
id: Cryobeaker
- type: Tag - type: Tag
id: ConveyorAssembly id: ConveyorAssembly

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -10,6 +10,9 @@
{ {
"name": "bed" "name": "bed"
}, },
{
"name": "bed-MED"
},
{ {
"name": "dogbed" "name": "dogbed"
}, },

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -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
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 922 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B