Diseases (#7057)
* Disease system first pass * Renamed HealthChange * First working version of diseases (wtf???) * Fix the cursed yaml initialization * Pop-Up effect * Generic status effect * Create copy of prototype * CureDiseaseEffect * Disease resistance * Spaceacillin * Nerf spaceacillin now that we know it works * Sneezing, Coughing, Snoughing * Fix queuing, prevent future issues * Disease protection * Disease outbreak event * Disease Reagent Cure * Chem cause disease effect * Disease artifacts * Try infect when interacting with diseased * Diseases don't have to be infectious * Talking without a mask does a snough * Temperature cure * Bedrest * DiseaseAdjustReagent * Tweak how disease statuses work to be a bit less shit * A few more diseases * Natural immunity (can't get the same disease twice) * Polished up some diseases, touched up spaceacillin production * Rebalanced transmission * Edit a few diseases, make disease cures support a minimum value * Nitrile gloves, more disease protection sources * Health scanner shows diseased status * Clean up disease system * Traitor item * Mouth swabs * Disease diagnoser machine * Support for clean samples * Vaccines + fixes * Pass on disease resistant clothes * More work on non-infectious diseases & vaccines * Handle dead bodies * Added the relatively CBT visualizer * Pass over diseases and their populators * Comment stuff * Readability cleanup * Add printing sound to diagnoser, fix printing bug * vaccinator sound, seal up some classes * Make disease protection equip detection not shit (thanks whoever wrote addaccentcomponent) * Mirror review * More review stuff * More mirror review stuff * Refactor snoughing * Redid report creator * Fix snough messages, new vaccinator sound * Mirror review naming * Woops, forgot the artifact * Add recipes and fills * Rebalance space cold and robovirus * Give lizarb disease interaction stuff * Tweak some stuff and move things around * Add diseases to mice (since animal vectors are interesting and can be used to make vaccines) * Remove unused reagent
29
Content.Client/Disease/DiseaseMachineSystem.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Content.Shared.Disease;
|
||||||
|
|
||||||
|
namespace Content.Client.Disease
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Controls client-side visuals for the
|
||||||
|
/// disease machines.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DiseaseMachineSystem : VisualizerSystem<DiseaseMachineVisualsComponent>
|
||||||
|
{
|
||||||
|
protected override void OnAppearanceChange(EntityUid uid, DiseaseMachineVisualsComponent component, ref AppearanceChangeEvent args)
|
||||||
|
{
|
||||||
|
if (TryComp(uid, out SpriteComponent? sprite)
|
||||||
|
&& args.Component.TryGetData(DiseaseMachineVisuals.IsOn, out bool isOn)
|
||||||
|
&& args.Component.TryGetData(DiseaseMachineVisuals.IsRunning, out bool isRunning))
|
||||||
|
{
|
||||||
|
var state = isRunning ? component.RunningState : component.IdleState;
|
||||||
|
sprite.LayerSetVisible(DiseaseMachineVisualLayers.IsOn, isOn);
|
||||||
|
sprite.LayerSetState(DiseaseMachineVisualLayers.IsRunning, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public enum DiseaseMachineVisualLayers : byte
|
||||||
|
{
|
||||||
|
IsOn,
|
||||||
|
IsRunning
|
||||||
|
}
|
||||||
15
Content.Client/Disease/DiseaseMachineVisualsComponent.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
namespace Content.Client.Disease;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Holds the idle and running state for machines to control
|
||||||
|
/// playing animtions on the client.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class DiseaseMachineVisualsComponent : Component
|
||||||
|
{
|
||||||
|
[DataField("idleState", required: true)]
|
||||||
|
public string IdleState = default!;
|
||||||
|
|
||||||
|
[DataField("runningState", required: true)]
|
||||||
|
public string RunningState = default!;
|
||||||
|
}
|
||||||
@@ -37,6 +37,10 @@ namespace Content.Client.Entry
|
|||||||
"Healing",
|
"Healing",
|
||||||
"Material",
|
"Material",
|
||||||
"RandomAppearance",
|
"RandomAppearance",
|
||||||
|
"DiseaseProtection",
|
||||||
|
"DiseaseDiagnoser",
|
||||||
|
"DiseaseVaccine",
|
||||||
|
"DiseaseVaccineCreator",
|
||||||
"Mineable",
|
"Mineable",
|
||||||
"RangedMagazine",
|
"RangedMagazine",
|
||||||
"Ammo",
|
"Ammo",
|
||||||
@@ -47,12 +51,15 @@ namespace Content.Client.Entry
|
|||||||
"ResearchClient",
|
"ResearchClient",
|
||||||
"IdCardConsole",
|
"IdCardConsole",
|
||||||
"ThermalRegulator",
|
"ThermalRegulator",
|
||||||
|
"DiseaseMachineRunning",
|
||||||
|
"DiseaseMachine",
|
||||||
"AtmosFixMarker",
|
"AtmosFixMarker",
|
||||||
"CablePlacer",
|
"CablePlacer",
|
||||||
"Drink",
|
"Drink",
|
||||||
"Food",
|
"Food",
|
||||||
"DeployableBarrier",
|
"DeployableBarrier",
|
||||||
"MagicMirror",
|
"MagicMirror",
|
||||||
|
"DiseaseSwab",
|
||||||
"FloorTile",
|
"FloorTile",
|
||||||
"RandomInsulation",
|
"RandomInsulation",
|
||||||
"Electrified",
|
"Electrified",
|
||||||
@@ -62,6 +69,7 @@ namespace Content.Client.Entry
|
|||||||
"Bloodstream",
|
"Bloodstream",
|
||||||
"TransformableContainer",
|
"TransformableContainer",
|
||||||
"Mind",
|
"Mind",
|
||||||
|
"DiseaseCarrier",
|
||||||
"StorageFill",
|
"StorageFill",
|
||||||
"Mop",
|
"Mop",
|
||||||
"Bucket",
|
"Bucket",
|
||||||
@@ -122,6 +130,7 @@ namespace Content.Client.Entry
|
|||||||
"RCD",
|
"RCD",
|
||||||
"RCDAmmo",
|
"RCDAmmo",
|
||||||
"CursedEntityStorage",
|
"CursedEntityStorage",
|
||||||
|
"DiseaseArtifact",
|
||||||
"Radio",
|
"Radio",
|
||||||
"GasArtifact",
|
"GasArtifact",
|
||||||
"SentienceTarget",
|
"SentienceTarget",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Robust.Client.AutoGenerated;
|
|||||||
using Robust.Client.UserInterface.CustomControls;
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
using Content.Shared.Damage.Prototypes;
|
using Content.Shared.Damage.Prototypes;
|
||||||
|
using Content.Shared.Disease.Components;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
@@ -35,7 +36,17 @@ namespace Content.Client.HealthAnalyzer.UI
|
|||||||
|
|
||||||
text.Append($"{Loc.GetString("health-analyzer-window-entity-health-text", ("entityName", entityName))}\n");
|
text.Append($"{Loc.GetString("health-analyzer-window-entity-health-text", ("entityName", entityName))}\n");
|
||||||
|
|
||||||
text.Append($"{Loc.GetString("health-analyzer-window-entity-damage-total-text", ("amount", damageable.TotalDamage))}\n");
|
/// Status Effects / Components
|
||||||
|
if (entities.HasComponent<DiseasedComponent>(msg.TargetEntity))
|
||||||
|
{
|
||||||
|
text.Append($"{Loc.GetString("disease-scanner-diseased")}\n");
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
text.Append($"{Loc.GetString("disease-scanner-not-diseased")}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Damage
|
||||||
|
text.Append($"\n{Loc.GetString("health-analyzer-window-entity-damage-total-text", ("amount", damageable.TotalDamage))}\n");
|
||||||
|
|
||||||
HashSet<string> shownTypes = new();
|
HashSet<string> shownTypes = new();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
@@ -10,6 +8,9 @@ using Content.Server.MoMMI;
|
|||||||
using Content.Server.Players;
|
using Content.Server.Players;
|
||||||
using Content.Server.Preferences.Managers;
|
using Content.Server.Preferences.Managers;
|
||||||
using Content.Server.Radio.EntitySystems;
|
using Content.Server.Radio.EntitySystems;
|
||||||
|
using Content.Server.Disease;
|
||||||
|
using Content.Server.Disease.Components;
|
||||||
|
using Content.Shared.Disease.Components;
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
@@ -22,10 +23,6 @@ using Robust.Server.Player;
|
|||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
using Robust.Shared.Log;
|
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Players;
|
using Robust.Shared.Players;
|
||||||
@@ -208,6 +205,11 @@ namespace Content.Server.Chat.Managers
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_entManager.HasComponent<DiseasedComponent>(source) && _entManager.TryGetComponent<DiseaseCarrierComponent>(source,out var carrier))
|
||||||
|
{
|
||||||
|
EntitySystem.Get<DiseaseSystem>().SneezeCough(source, _random.Pick(carrier.Diseases), string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
if (MessageCharacterLimit(source, message))
|
if (MessageCharacterLimit(source, message))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|||||||
32
Content.Server/Chemistry/ReagentEffects/ChemCauseDisease.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
|
using Content.Server.Disease;
|
||||||
|
using Content.Shared.Disease;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
|
namespace Content.Server.Chemistry.ReagentEffects
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Default metabolism for medicine reagents.
|
||||||
|
/// </summary>
|
||||||
|
[UsedImplicitly]
|
||||||
|
public sealed class ChemCauseDisease : ReagentEffect
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Chance it has each tick to cause disease, between 0 and 1
|
||||||
|
/// </summary>
|
||||||
|
[DataField("causeChance")]
|
||||||
|
public float CauseChance = 0.15f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The disease to add.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("disease", customTypeSerializer: typeof(PrototypeIdSerializer<DiseasePrototype>))]
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public string Disease = string.Empty;
|
||||||
|
public override void Effect(ReagentEffectArgs args)
|
||||||
|
{
|
||||||
|
EntitySystem.Get<DiseaseSystem>().TryAddDisease(null, null, Disease, args.SolutionEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
Content.Server/Chemistry/ReagentEffects/ChemCureDisease.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
|
using Content.Server.Disease;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
|
namespace Content.Server.Chemistry.ReagentEffects
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Default metabolism for medicine reagents.
|
||||||
|
/// </summary>
|
||||||
|
[UsedImplicitly]
|
||||||
|
public sealed class ChemCureDisease : ReagentEffect
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Chance it has each tick to cure a disease, between 0 and 1
|
||||||
|
/// </summary>
|
||||||
|
[DataField("cureChance")]
|
||||||
|
public float CureChance = 0.15f;
|
||||||
|
|
||||||
|
public override void Effect(ReagentEffectArgs args)
|
||||||
|
{
|
||||||
|
var ev = new CureDiseaseAttemptEvent(CureChance);
|
||||||
|
args.EntityManager.EventBus.RaiseLocalEvent(args.SolutionEntity, ev, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using Content.Shared.Chemistry.Reagent;
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
|||||||
36
Content.Server/Disease/Components/DiseaseCarrierComponent.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using Content.Shared.Disease;
|
||||||
|
|
||||||
|
namespace Content.Server.Disease.Components
|
||||||
|
{
|
||||||
|
[RegisterComponent]
|
||||||
|
/// <summary>
|
||||||
|
/// Allows the enity to be infected with diseases.
|
||||||
|
/// Please use only on mobs.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DiseaseCarrierComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Shows the CURRENT diseases on the carrier
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public List<DiseasePrototype> Diseases = new();
|
||||||
|
/// <summary>
|
||||||
|
/// The carrier's resistance to disease
|
||||||
|
/// </summary>
|
||||||
|
[DataField("diseaseResist")]
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float DiseaseResist = 0f;
|
||||||
|
/// <summary>
|
||||||
|
/// Diseases the carrier has had, used for immunity.
|
||||||
|
/// <summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public List<DiseasePrototype> PastDiseases = new();
|
||||||
|
/// <summary>
|
||||||
|
/// All the diseases the carrier has or has had.
|
||||||
|
/// Checked against when trying to add a disease
|
||||||
|
/// <summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public List<DiseasePrototype> AllDiseases => PastDiseases.Concat(Diseases).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Content.Server.Disease.Components
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// To give the disease diagnosing machine specific behavior
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class DiseaseDiagnoserComponent : Component
|
||||||
|
{}
|
||||||
|
}
|
||||||
31
Content.Server/Disease/Components/DiseaseMachineComponent.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using Content.Shared.Disease;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
|
namespace Content.Server.Disease.Components
|
||||||
|
{
|
||||||
|
[RegisterComponent]
|
||||||
|
/// <summary>
|
||||||
|
/// For shared behavior between both disease machines
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DiseaseMachineComponent : Component
|
||||||
|
{
|
||||||
|
[DataField("delay")]
|
||||||
|
public float Delay = 5f;
|
||||||
|
/// <summary>
|
||||||
|
/// How much time we've accumulated processing
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public float Accumulator = 0f;
|
||||||
|
/// <summary>
|
||||||
|
/// The disease prototype currently being diagnosed
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public DiseasePrototype? Disease;
|
||||||
|
/// <summary>
|
||||||
|
/// What the machine will spawn
|
||||||
|
/// </summary>
|
||||||
|
[DataField("machineOutput", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>), required: true)]
|
||||||
|
public string MachineOutput = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Content.Server.Disease.Components
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// For EntityQuery to keep track of which machines are running
|
||||||
|
/// <summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class DiseaseMachineRunningComponent : Component
|
||||||
|
{}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
namespace Content.Server.Disease.Components
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Value added to clothing to give its wearer
|
||||||
|
/// protection against infection from diseases
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class DiseaseProtectionComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Float value between 0 and 1, will be subtracted
|
||||||
|
/// from the infection chance (which is base 0.7)
|
||||||
|
/// Reference guide is a full biosuit w/gloves & mask
|
||||||
|
/// should add up to exactly 0.7
|
||||||
|
/// </summary>
|
||||||
|
[DataField("protection")]
|
||||||
|
public float Protection = 0.1f;
|
||||||
|
/// <summary>
|
||||||
|
/// Is the component currently being worn and affecting someone's disease
|
||||||
|
/// resistance? Making the unequip check not totally CBT
|
||||||
|
/// </summary>
|
||||||
|
public bool IsActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
33
Content.Server/Disease/Components/DiseaseSwabComponent.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using System.Threading;
|
||||||
|
using Content.Shared.Disease;
|
||||||
|
|
||||||
|
namespace Content.Server.Disease.Components
|
||||||
|
{
|
||||||
|
[RegisterComponent]
|
||||||
|
/// <summary>
|
||||||
|
/// For mouth swabs used to collect and process
|
||||||
|
/// disease samples.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DiseaseSwabComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// How long it takes to swab someone.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("swabDelay")]
|
||||||
|
[ViewVariables]
|
||||||
|
public float SwabDelay = 2f;
|
||||||
|
/// <summary>
|
||||||
|
/// If this swab has been used
|
||||||
|
/// </summary>
|
||||||
|
public bool Used = false;
|
||||||
|
/// <summary>
|
||||||
|
/// Token for interrupting swabbing do after.
|
||||||
|
/// </summary>
|
||||||
|
public CancellationTokenSource? CancelToken;
|
||||||
|
/// <summary>
|
||||||
|
/// The disease prototype currently on the swab
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public DiseasePrototype? Disease;
|
||||||
|
}
|
||||||
|
}
|
||||||
33
Content.Server/Disease/Components/DiseaseVaccineComponent.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using System.Threading;
|
||||||
|
using Content.Shared.Disease;
|
||||||
|
|
||||||
|
namespace Content.Server.Disease.Components
|
||||||
|
{
|
||||||
|
[RegisterComponent]
|
||||||
|
/// <summary>
|
||||||
|
/// For disease vaccines
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DiseaseVaccineComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// How long it takes to inject someone
|
||||||
|
/// </summary>
|
||||||
|
[DataField("injectDelay")]
|
||||||
|
[ViewVariables]
|
||||||
|
public float InjectDelay = 2f;
|
||||||
|
/// <summary>
|
||||||
|
/// If this vaccine has been used
|
||||||
|
/// </summary>
|
||||||
|
public bool Used = false;
|
||||||
|
/// <summary>
|
||||||
|
/// Token for interrupting injection do after.
|
||||||
|
/// </summary>
|
||||||
|
public CancellationTokenSource? CancelToken;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The disease prototype currently on the vaccine
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public DiseasePrototype? Disease;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Content.Server.Disease.Components
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Controls disease machine behavior specific to the
|
||||||
|
/// vaccine creating machine
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class DiseaseVaccineCreatorComponent : Component
|
||||||
|
{}
|
||||||
|
}
|
||||||
33
Content.Server/Disease/Cures/DiseaseBedrestCure.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using Content.Shared.Disease;
|
||||||
|
using Content.Server.Buckle.Components;
|
||||||
|
|
||||||
|
namespace Content.Server.Disease.Cures
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Cures the disease after a certain amount of time
|
||||||
|
/// strapped.
|
||||||
|
/// </summary>
|
||||||
|
/// TODO: Revisit after bed pr merged
|
||||||
|
public sealed class DiseaseBedrestCure : DiseaseCure
|
||||||
|
{
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public int Ticker = 0;
|
||||||
|
[DataField("maxLength", required: true)]
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public int MaxLength = 60;
|
||||||
|
|
||||||
|
public override bool Cure(DiseaseEffectArgs args)
|
||||||
|
{
|
||||||
|
if (!args.EntityManager.TryGetComponent<BuckleComponent>(args.DiseasedEntity, out var buckle))
|
||||||
|
return false;
|
||||||
|
if (buckle.Buckled)
|
||||||
|
Ticker++;
|
||||||
|
return Ticker >= MaxLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string CureText()
|
||||||
|
{
|
||||||
|
return (Loc.GetString("diagnoser-cure-bedrest", ("time", MaxLength)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
34
Content.Server/Disease/Cures/DiseaseBodyTemperatureCure.cs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
using Content.Server.Temperature.Components;
|
||||||
|
using Content.Shared.Disease;
|
||||||
|
|
||||||
|
namespace Content.Server.Disease.Cures
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Cures the disease if temperature is within certain bounds.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DiseaseBodyTemperatureCure : DiseaseCure
|
||||||
|
{
|
||||||
|
[DataField("min")]
|
||||||
|
public float Min = 0;
|
||||||
|
|
||||||
|
[DataField("max")]
|
||||||
|
public float Max = float.MaxValue;
|
||||||
|
public override bool Cure(DiseaseEffectArgs args)
|
||||||
|
{
|
||||||
|
if (!args.EntityManager.TryGetComponent(args.DiseasedEntity, out TemperatureComponent temp))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return temp.CurrentTemperature > Min && temp.CurrentTemperature < float.MaxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string CureText()
|
||||||
|
{
|
||||||
|
if (Min == 0)
|
||||||
|
return Loc.GetString("diagnoser-cure-temp-max", ("max", Math.Round(Max)));
|
||||||
|
if (Max == float.MaxValue)
|
||||||
|
return Loc.GetString("diagnoser-cure-temp-min", ("min", Math.Round(Min)));
|
||||||
|
|
||||||
|
return Loc.GetString("diagnoser-cure-temp-both", ("max", Math.Round(Max)), ("min", Math.Round(Min)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
31
Content.Server/Disease/Cures/DiseaseJustWaitCure.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using Content.Shared.Disease;
|
||||||
|
|
||||||
|
namespace Content.Server.Disease.Cures
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Automatically removes the disease after a
|
||||||
|
/// certain amount of time.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DiseaseJustWaitCure : DiseaseCure
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// All of these are in seconds
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public int Ticker = 0;
|
||||||
|
[DataField("maxLength", required: true)]
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public int MaxLength = 150;
|
||||||
|
|
||||||
|
public override bool Cure(DiseaseEffectArgs args)
|
||||||
|
{
|
||||||
|
Ticker++;
|
||||||
|
return Ticker >= MaxLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string CureText()
|
||||||
|
{
|
||||||
|
return Loc.GetString("diagnoser-cure-wait", ("time", MaxLength));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
Content.Server/Disease/Cures/DiseaseReagentCure.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using Content.Shared.Disease;
|
||||||
|
using Content.Shared.FixedPoint;
|
||||||
|
using Content.Server.Body.Components;
|
||||||
|
|
||||||
|
namespace Content.Server.Disease.Cures
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Cures the disease if a certain amount of reagent
|
||||||
|
/// is in the host's chemstream.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DiseaseReagentCure : DiseaseCure
|
||||||
|
{
|
||||||
|
[DataField("min")]
|
||||||
|
public FixedPoint2 Min = 5;
|
||||||
|
[DataField("reagent")]
|
||||||
|
public string? Reagent;
|
||||||
|
|
||||||
|
public override bool Cure(DiseaseEffectArgs args)
|
||||||
|
{
|
||||||
|
if (!args.EntityManager.TryGetComponent<BloodstreamComponent>(args.DiseasedEntity, out var bloodstream))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var quant = FixedPoint2.Zero;
|
||||||
|
if (Reagent != null && bloodstream.ChemicalSolution.ContainsReagent(Reagent))
|
||||||
|
{
|
||||||
|
quant = bloodstream.ChemicalSolution.GetReagentQuantity(Reagent);
|
||||||
|
}
|
||||||
|
return quant >= Min;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string CureText()
|
||||||
|
{
|
||||||
|
if (Reagent == null)
|
||||||
|
return string.Empty;
|
||||||
|
return (Loc.GetString("diagnoser-cure-reagent", ("units", Min), ("reagent", Reagent)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
415
Content.Server/Disease/DiseaseDiagnosisSystem.cs
Normal file
@@ -0,0 +1,415 @@
|
|||||||
|
using System.Threading;
|
||||||
|
using Content.Server.Disease.Components;
|
||||||
|
using Content.Shared.Disease;
|
||||||
|
using Content.Shared.Disease.Components;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using Content.Shared.Inventory;
|
||||||
|
using Content.Shared.Examine;
|
||||||
|
using Content.Server.DoAfter;
|
||||||
|
using Content.Server.Popups;
|
||||||
|
using Content.Server.Hands.Components;
|
||||||
|
using Content.Server.Nutrition.EntitySystems;
|
||||||
|
using Content.Server.Paper;
|
||||||
|
using Content.Server.Tools.Components;
|
||||||
|
using Content.Server.Power.Components;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Server.Disease
|
||||||
|
{
|
||||||
|
/// Everything that's about disease diangosis and machines is in here
|
||||||
|
|
||||||
|
public sealed class DiseaseDiagnosisSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
||||||
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
SubscribeLocalEvent<DiseaseSwabComponent, AfterInteractEvent>(OnAfterInteract);
|
||||||
|
SubscribeLocalEvent<DiseaseSwabComponent, ExaminedEvent>(OnExamined);
|
||||||
|
SubscribeLocalEvent<DiseaseDiagnoserComponent, AfterInteractUsingEvent>(OnAfterInteractUsing);
|
||||||
|
SubscribeLocalEvent<DiseaseVaccineCreatorComponent, AfterInteractUsingEvent>(OnAfterInteractUsingVaccine);
|
||||||
|
/// Visuals
|
||||||
|
SubscribeLocalEvent<DiseaseMachineComponent, PowerChangedEvent>(OnPowerChanged);
|
||||||
|
/// Private Events
|
||||||
|
SubscribeLocalEvent<DiseaseDiagnoserComponent, DiseaseMachineFinishedEvent>(OnDiagnoserFinished);
|
||||||
|
SubscribeLocalEvent<DiseaseVaccineCreatorComponent, DiseaseMachineFinishedEvent>(OnVaccinatorFinished);
|
||||||
|
SubscribeLocalEvent<TargetSwabSuccessfulEvent>(OnTargetSwabSuccessful);
|
||||||
|
SubscribeLocalEvent<SwabCancelledEvent>(OnSwabCancelled);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Queue<EntityUid> AddQueue = new();
|
||||||
|
private Queue<EntityUid> RemoveQueue = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This handles running disease machines
|
||||||
|
/// to handle their delay and visuals.
|
||||||
|
/// </summary>
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
foreach (var uid in AddQueue)
|
||||||
|
EnsureComp<DiseaseMachineRunningComponent>(uid);
|
||||||
|
|
||||||
|
AddQueue.Clear();
|
||||||
|
foreach (var uid in RemoveQueue)
|
||||||
|
RemComp<DiseaseMachineRunningComponent>(uid);
|
||||||
|
|
||||||
|
RemoveQueue.Clear();
|
||||||
|
|
||||||
|
foreach (var (runningComp, diseaseMachine) in EntityQuery<DiseaseMachineRunningComponent, DiseaseMachineComponent>(false))
|
||||||
|
{
|
||||||
|
if (diseaseMachine.Accumulator < diseaseMachine.Delay)
|
||||||
|
{
|
||||||
|
diseaseMachine.Accumulator += frameTime;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
diseaseMachine.Accumulator = 0;
|
||||||
|
var ev = new DiseaseMachineFinishedEvent(diseaseMachine);
|
||||||
|
RaiseLocalEvent(diseaseMachine.Owner, ev, false);
|
||||||
|
RemoveQueue.Enqueue(diseaseMachine.Owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Event Handlers
|
||||||
|
///
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This handles using swabs on other people
|
||||||
|
/// and checks that the swab isn't already used
|
||||||
|
/// and the other person's mouth is accessible
|
||||||
|
/// and then adds a random disease from that person
|
||||||
|
/// to the swab if they have any
|
||||||
|
/// </summary>
|
||||||
|
private void OnAfterInteract(EntityUid uid, DiseaseSwabComponent swab, AfterInteractEvent args)
|
||||||
|
{
|
||||||
|
if (swab.CancelToken != null)
|
||||||
|
{
|
||||||
|
swab.CancelToken.Cancel();
|
||||||
|
swab.CancelToken = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (args.Target == null || !args.CanReach)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp<DiseaseCarrierComponent>(args.Target, out var carrier))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (swab.Used)
|
||||||
|
{
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("swab-already-used"), args.User, Filter.Entities(args.User));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_inventorySystem.TryGetSlotEntity(args.Target.Value, "mask", out var maskUid) &&
|
||||||
|
EntityManager.TryGetComponent<IngestionBlockerComponent>(maskUid, out var blocker) &&
|
||||||
|
blocker.Enabled)
|
||||||
|
{
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("swab-mask-blocked", ("target", args.Target), ("mask", maskUid)), args.User, Filter.Entities(args.User));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
swab.CancelToken = new CancellationTokenSource();
|
||||||
|
_doAfterSystem.DoAfter(new DoAfterEventArgs(args.User, swab.SwabDelay, swab.CancelToken.Token, target: args.Target)
|
||||||
|
{
|
||||||
|
BroadcastFinishedEvent = new TargetSwabSuccessfulEvent(args.User, args.Target, swab, carrier),
|
||||||
|
BroadcastCancelledEvent = new SwabCancelledEvent(swab),
|
||||||
|
BreakOnTargetMove = true,
|
||||||
|
BreakOnUserMove = true,
|
||||||
|
BreakOnStun = true,
|
||||||
|
NeedHand = true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This handles the disease diagnoser machine up
|
||||||
|
/// until it's turned on. It has some slight
|
||||||
|
/// differences in checks from the vaccinator.
|
||||||
|
/// </summary>
|
||||||
|
private void OnAfterInteractUsing(EntityUid uid, DiseaseDiagnoserComponent component, AfterInteractUsingEvent args)
|
||||||
|
{
|
||||||
|
var machine = Comp<DiseaseMachineComponent>(uid);
|
||||||
|
if (args.Handled || !args.CanReach)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (TryComp<ApcPowerReceiverComponent>(uid, out var power) && !power.Powered)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!HasComp<HandsComponent>(args.User) || HasComp<ToolComponent>(args.Used)) // Don't want to accidentally breach wrenching or whatever
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp<DiseaseSwabComponent>(args.Used, out var swab))
|
||||||
|
{
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("diagnoser-cant-use-swab", ("machine", uid), ("swab", args.Used)), uid, Filter.Entities(args.User));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("diagnoser-insert-swab", ("machine", uid), ("swab", args.Used)), uid, Filter.Entities(args.User));
|
||||||
|
|
||||||
|
|
||||||
|
machine.Disease = swab.Disease;
|
||||||
|
EntityManager.DeleteEntity(args.Used);
|
||||||
|
|
||||||
|
AddQueue.Enqueue(uid);
|
||||||
|
UpdateAppearance(uid, true, true);
|
||||||
|
SoundSystem.Play(Filter.Pvs(uid), "/Audio/Machines/diagnoser_printing.ogg", uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This handles the vaccinator machine up
|
||||||
|
/// until it's turned on. It has some slight
|
||||||
|
/// differences in checks from the diagnoser.
|
||||||
|
/// </summary>
|
||||||
|
private void OnAfterInteractUsingVaccine(EntityUid uid, DiseaseVaccineCreatorComponent component, AfterInteractUsingEvent args)
|
||||||
|
{
|
||||||
|
if (args.Handled || !args.CanReach)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (TryComp<ApcPowerReceiverComponent>(uid, out var power) && !power.Powered)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!HasComp<HandsComponent>(args.User) || HasComp<ToolComponent>(args.Used)) //This check ensures tools don't break without yaml ordering jank
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp<DiseaseSwabComponent>(args.Used, out var swab) || swab.Disease == null || !swab.Disease.Infectious)
|
||||||
|
{
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("diagnoser-cant-use-swab", ("machine", uid), ("swab", args.Used)), uid, Filter.Entities(args.User));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("diagnoser-insert-swab", ("machine", uid), ("swab", args.Used)), uid, Filter.Entities(args.User));
|
||||||
|
var machine = Comp<DiseaseMachineComponent>(uid);
|
||||||
|
machine.Disease = swab.Disease;
|
||||||
|
EntityManager.DeleteEntity(args.Used);
|
||||||
|
|
||||||
|
AddQueue.Enqueue(uid);
|
||||||
|
UpdateAppearance(uid, true, true);
|
||||||
|
SoundSystem.Play(Filter.Pvs(uid), "/Audio/Machines/vaccinator_running.ogg", uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This handles swab examination text
|
||||||
|
/// so you can tell if they are used or not.
|
||||||
|
/// </summary>
|
||||||
|
private void OnExamined(EntityUid uid, DiseaseSwabComponent swab, ExaminedEvent args)
|
||||||
|
{
|
||||||
|
if (args.IsInDetailsRange)
|
||||||
|
{
|
||||||
|
if (swab.Used)
|
||||||
|
args.PushMarkup(Loc.GetString("swab-used"));
|
||||||
|
else
|
||||||
|
args.PushMarkup(Loc.GetString("swab-unused"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Helper functions
|
||||||
|
///
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This assembles a disease report
|
||||||
|
/// With its basic details and
|
||||||
|
/// specific cures (i.e. not spaceacillin).
|
||||||
|
/// The cure resist field tells you how
|
||||||
|
/// effective spaceacillin etc will be.
|
||||||
|
/// </summary>
|
||||||
|
private FormattedMessage AssembleDiseaseReport(DiseasePrototype disease)
|
||||||
|
{
|
||||||
|
FormattedMessage report = new();
|
||||||
|
report.AddMarkup(Loc.GetString("diagnoser-disease-report-name", ("disease", disease.Name)));
|
||||||
|
report.PushNewline();
|
||||||
|
|
||||||
|
if (disease.Infectious)
|
||||||
|
{
|
||||||
|
report.AddMarkup(Loc.GetString("diagnoser-disease-report-infectious"));
|
||||||
|
report.PushNewline();
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
report.AddMarkup(Loc.GetString("diagnoser-disease-report-not-infectious"));
|
||||||
|
report.PushNewline();
|
||||||
|
}
|
||||||
|
string cureResistLine = string.Empty;
|
||||||
|
cureResistLine += disease.CureResist switch
|
||||||
|
{
|
||||||
|
< 0f => Loc.GetString("diagnoser-disease-report-cureresist-none"),
|
||||||
|
<= 0.05f => Loc.GetString("diagnoser-disease-report-cureresist-low"),
|
||||||
|
<= 0.14f => Loc.GetString("diagnoser-disease-report-cureresist-medium"),
|
||||||
|
_ => Loc.GetString("diagnoser-disease-report-cureresist-high")
|
||||||
|
};
|
||||||
|
report.AddMarkup(cureResistLine);
|
||||||
|
report.PushNewline();
|
||||||
|
|
||||||
|
/// Add Cures
|
||||||
|
if (disease.Cures.Count == 0)
|
||||||
|
{
|
||||||
|
report.AddMarkup(Loc.GetString("diagnoser-no-cures"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
report.PushNewline();
|
||||||
|
report.AddMarkup(Loc.GetString("diagnoser-cure-has"));
|
||||||
|
report.PushNewline();
|
||||||
|
|
||||||
|
foreach (var cure in disease.Cures)
|
||||||
|
{
|
||||||
|
report.AddMarkup(cure.CureText());
|
||||||
|
report.PushNewline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
///
|
||||||
|
/// Appearance stuff
|
||||||
|
///
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appearance helper function to
|
||||||
|
/// set the component's power and running states.
|
||||||
|
/// </summary>
|
||||||
|
private void UpdateAppearance(EntityUid uid, bool isOn, bool isRunning)
|
||||||
|
{
|
||||||
|
if (!TryComp<AppearanceComponent>(uid, out var appearance))
|
||||||
|
return;
|
||||||
|
|
||||||
|
appearance.SetData(DiseaseMachineVisuals.IsOn, isOn);
|
||||||
|
appearance.SetData(DiseaseMachineVisuals.IsRunning, isRunning);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Makes sure the machine is visually off/on.
|
||||||
|
/// </summary>
|
||||||
|
private void OnPowerChanged(EntityUid uid, DiseaseMachineComponent component, PowerChangedEvent args)
|
||||||
|
{
|
||||||
|
UpdateAppearance(uid, args.Powered, false);
|
||||||
|
}
|
||||||
|
///
|
||||||
|
/// Private events
|
||||||
|
///
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies a disease prototype to the swab
|
||||||
|
/// after the doafter completes.
|
||||||
|
/// </summary>
|
||||||
|
private void OnTargetSwabSuccessful(TargetSwabSuccessfulEvent args)
|
||||||
|
{
|
||||||
|
if (args.Target == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.Swab.Used = true;
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("swab-swabbed", ("target", args.Target)), args.Target.Value, Filter.Entities(args.User));
|
||||||
|
|
||||||
|
if (args.Swab.Disease != null || args.Carrier.Diseases.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.Swab.Disease = _random.Pick(args.Carrier.Diseases);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancels the swab doafter if needed.
|
||||||
|
/// </summary>
|
||||||
|
private static void OnSwabCancelled(SwabCancelledEvent args)
|
||||||
|
{
|
||||||
|
args.Swab.CancelToken = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prints a diagnostic report with its findings.
|
||||||
|
/// Also cancels the animation.
|
||||||
|
/// </summary>
|
||||||
|
private void OnDiagnoserFinished(EntityUid uid, DiseaseDiagnoserComponent component, DiseaseMachineFinishedEvent args)
|
||||||
|
{
|
||||||
|
var power = Comp<ApcPowerReceiverComponent>(uid);
|
||||||
|
UpdateAppearance(uid, power.Powered, false);
|
||||||
|
// spawn a piece of paper.
|
||||||
|
var printed = EntityManager.SpawnEntity(args.Machine.MachineOutput, Transform(uid).Coordinates);
|
||||||
|
|
||||||
|
if (!TryComp<PaperComponent>(printed, out var paper))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var reportTitle = string.Empty;
|
||||||
|
FormattedMessage contents = new();
|
||||||
|
if (args.Machine.Disease != null)
|
||||||
|
{
|
||||||
|
reportTitle = Loc.GetString("diagnoser-disease-report", ("disease", args.Machine.Disease.Name));
|
||||||
|
contents = AssembleDiseaseReport(args.Machine.Disease);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
reportTitle = Loc.GetString("diagnoser-disease-report-none");
|
||||||
|
contents.AddMarkup(Loc.GetString("diagnoser-disease-report-none-contents"));
|
||||||
|
}
|
||||||
|
MetaData(printed).EntityName = reportTitle;
|
||||||
|
|
||||||
|
paper.SetContent(contents.ToMarkup());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prints a vaccine that will vaccinate
|
||||||
|
/// against the disease on the inserted swab.
|
||||||
|
/// <summary>
|
||||||
|
private void OnVaccinatorFinished(EntityUid uid, DiseaseVaccineCreatorComponent component, DiseaseMachineFinishedEvent args)
|
||||||
|
{
|
||||||
|
var power = Comp<ApcPowerReceiverComponent>(uid);
|
||||||
|
UpdateAppearance(uid, power.Powered, false);
|
||||||
|
|
||||||
|
// spawn a vaccine
|
||||||
|
var vaxx = EntityManager.SpawnEntity(args.Machine.MachineOutput, Transform(uid).Coordinates);
|
||||||
|
|
||||||
|
if (!TryComp<DiseaseVaccineComponent>(vaxx, out var vaxxComp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
vaxxComp.Disease = args.Machine.Disease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancels the mouth-swabbing doafter
|
||||||
|
/// </summary>
|
||||||
|
private sealed class SwabCancelledEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public readonly DiseaseSwabComponent Swab;
|
||||||
|
public SwabCancelledEvent(DiseaseSwabComponent swab)
|
||||||
|
{
|
||||||
|
Swab = swab;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fires if the doafter for swabbing someone's mouth succeeds
|
||||||
|
/// </summary>
|
||||||
|
private sealed class TargetSwabSuccessfulEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public EntityUid User { get; }
|
||||||
|
public EntityUid? Target { get; }
|
||||||
|
public DiseaseSwabComponent Swab { get; }
|
||||||
|
|
||||||
|
public DiseaseCarrierComponent Carrier { get; }
|
||||||
|
|
||||||
|
public TargetSwabSuccessfulEvent(EntityUid user, EntityUid? target, DiseaseSwabComponent swab, DiseaseCarrierComponent carrier)
|
||||||
|
{
|
||||||
|
User = user;
|
||||||
|
Target = target;
|
||||||
|
Swab = swab;
|
||||||
|
Carrier = carrier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fires when a disease machine is done
|
||||||
|
/// with its production delay and ready to
|
||||||
|
/// create a report or vaccine
|
||||||
|
/// </summary>
|
||||||
|
private sealed class DiseaseMachineFinishedEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public DiseaseMachineComponent Machine {get;}
|
||||||
|
public DiseaseMachineFinishedEvent(DiseaseMachineComponent machine)
|
||||||
|
{
|
||||||
|
Machine = machine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
442
Content.Server/Disease/DiseaseSystem.cs
Normal file
@@ -0,0 +1,442 @@
|
|||||||
|
using System.Threading;
|
||||||
|
using Content.Shared.Disease;
|
||||||
|
using Content.Shared.Disease.Components;
|
||||||
|
using Content.Server.Disease.Components;
|
||||||
|
using Content.Server.Clothing.Components;
|
||||||
|
using Content.Shared.MobState.Components;
|
||||||
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.Inventory;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using Content.Server.Popups;
|
||||||
|
using Content.Server.DoAfter;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
using Robust.Shared.Serialization.Manager;
|
||||||
|
using Content.Shared.Inventory.Events;
|
||||||
|
using Content.Server.Nutrition.EntitySystems;
|
||||||
|
|
||||||
|
namespace Content.Server.Disease
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles disease propagation & curing
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DiseaseSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] private readonly ISerializationManager _serializationManager = default!;
|
||||||
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
||||||
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||||
|
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||||
|
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
SubscribeLocalEvent<DiseaseCarrierComponent, CureDiseaseAttemptEvent>(OnTryCureDisease);
|
||||||
|
SubscribeLocalEvent<DiseasedComponent, InteractHandEvent>(OnInteractDiseasedHand);
|
||||||
|
SubscribeLocalEvent<DiseasedComponent, InteractUsingEvent>(OnInteractDiseasedUsing);
|
||||||
|
SubscribeLocalEvent<DiseaseProtectionComponent, GotEquippedEvent>(OnEquipped);
|
||||||
|
SubscribeLocalEvent<DiseaseProtectionComponent, GotUnequippedEvent>(OnUnequipped);
|
||||||
|
SubscribeLocalEvent<DiseaseVaccineComponent, AfterInteractEvent>(OnAfterInteract);
|
||||||
|
SubscribeLocalEvent<DiseaseVaccineComponent, ExaminedEvent>(OnExamined);
|
||||||
|
/// Private events stuff
|
||||||
|
SubscribeLocalEvent<TargetVaxxSuccessfulEvent>(OnTargetVaxxSuccessful);
|
||||||
|
SubscribeLocalEvent<VaxxCancelledEvent>(OnVaxxCancelled);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Queue<EntityUid> AddQueue = new();
|
||||||
|
private Queue<(DiseaseCarrierComponent carrier, DiseasePrototype disease)> CureQueue = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// First, adds or removes diseased component from the queues and clears them.
|
||||||
|
/// Then, iterates over every diseased component to check for their effects
|
||||||
|
/// and cures
|
||||||
|
/// </summary>
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
foreach (var entity in AddQueue)
|
||||||
|
EnsureComp<DiseasedComponent>(entity);
|
||||||
|
AddQueue.Clear();
|
||||||
|
|
||||||
|
foreach (var tuple in CureQueue)
|
||||||
|
{
|
||||||
|
if (tuple.carrier.Diseases.Count == 1) //This is reliable unlike testing Count == 0 right after removal for reasons I don't quite get
|
||||||
|
RemComp<DiseasedComponent>(tuple.carrier.Owner);
|
||||||
|
tuple.carrier.PastDiseases.Add(tuple.disease);
|
||||||
|
tuple.carrier.Diseases.Remove(tuple.disease);
|
||||||
|
}
|
||||||
|
CureQueue.Clear();
|
||||||
|
|
||||||
|
foreach (var (diseasedComp, carrierComp, mobState) in EntityQuery<DiseasedComponent, DiseaseCarrierComponent, MobStateComponent>(false))
|
||||||
|
{
|
||||||
|
if (mobState.IsDead())
|
||||||
|
{
|
||||||
|
if (_random.Prob(0.005f * frameTime)) //Mean time to remove is 200 seconds per disease
|
||||||
|
CureDisease(carrierComp, _random.Pick(carrierComp.Diseases));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(var disease in carrierComp.Diseases)
|
||||||
|
{
|
||||||
|
var args = new DiseaseEffectArgs(carrierComp.Owner, disease, EntityManager);
|
||||||
|
disease.Accumulator += frameTime;
|
||||||
|
if (disease.Accumulator >= disease.TickTime)
|
||||||
|
{
|
||||||
|
disease.Accumulator -= disease.TickTime;
|
||||||
|
foreach (var cure in disease.Cures)
|
||||||
|
{
|
||||||
|
if (cure.Cure(args))
|
||||||
|
CureDisease(carrierComp, disease);
|
||||||
|
}
|
||||||
|
foreach (var effect in disease.Effects)
|
||||||
|
{
|
||||||
|
if (_random.Prob(effect.Probability))
|
||||||
|
effect.Effect(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Event Handlers
|
||||||
|
///
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used when something is trying to cure ANY disease on the target,
|
||||||
|
/// not for special disease interactions. Randomly
|
||||||
|
/// tries to cure every disease on the target.
|
||||||
|
/// </summary>
|
||||||
|
private void OnTryCureDisease(EntityUid uid, DiseaseCarrierComponent component, CureDiseaseAttemptEvent args)
|
||||||
|
{
|
||||||
|
foreach (var disease in component.Diseases)
|
||||||
|
{
|
||||||
|
var cureProb = ((args.CureChance / component.Diseases.Count) - disease.CureResist);
|
||||||
|
if (cureProb < 0)
|
||||||
|
return;
|
||||||
|
if (cureProb > 1)
|
||||||
|
{
|
||||||
|
CureDisease(component, disease);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_random.Prob(cureProb))
|
||||||
|
{
|
||||||
|
CureDisease(component, disease);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when a component with disease protection
|
||||||
|
/// is equipped so it can be added to the person's
|
||||||
|
/// total disease resistance
|
||||||
|
/// </summary>
|
||||||
|
private void OnEquipped(EntityUid uid, DiseaseProtectionComponent component, GotEquippedEvent args)
|
||||||
|
{
|
||||||
|
/// This only works on clothing
|
||||||
|
if (!TryComp<ClothingComponent>(uid, out var clothing))
|
||||||
|
return;
|
||||||
|
/// Is the clothing in its actual slot?
|
||||||
|
if (!clothing.SlotFlags.HasFlag(args.SlotFlags))
|
||||||
|
return;
|
||||||
|
/// Give the user the component's disease resist
|
||||||
|
if(TryComp<DiseaseCarrierComponent>(args.Equipee, out var carrier))
|
||||||
|
carrier.DiseaseResist += component.Protection;
|
||||||
|
/// Set the component to active to the unequip check isn't CBT
|
||||||
|
component.IsActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when a component with disease protection
|
||||||
|
/// is unequipped so it can be removed from the person's
|
||||||
|
/// total disease resistance
|
||||||
|
/// </summary>
|
||||||
|
private void OnUnequipped(EntityUid uid, DiseaseProtectionComponent component, GotUnequippedEvent args)
|
||||||
|
{
|
||||||
|
/// Only undo the resistance if it was affecting the user
|
||||||
|
if (!component.IsActive)
|
||||||
|
return;
|
||||||
|
if(TryComp<DiseaseCarrierComponent>(args.Equipee, out var carrier))
|
||||||
|
carrier.DiseaseResist -= component.Protection;
|
||||||
|
component.IsActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when it's already decided a disease will be cured
|
||||||
|
/// so it can be safely queued up to be removed from the target
|
||||||
|
/// and added to past disease history (for immunity)
|
||||||
|
/// </summary>
|
||||||
|
private void CureDisease(DiseaseCarrierComponent carrier, DiseasePrototype disease)
|
||||||
|
{
|
||||||
|
var CureTuple = (carrier, disease);
|
||||||
|
CureQueue.Enqueue(CureTuple);
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("disease-cured"), carrier.Owner, Filter.Entities(carrier.Owner));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when someone interacts with a diseased person with an empty hand
|
||||||
|
/// to check if they get infected
|
||||||
|
/// </summary>
|
||||||
|
private void OnInteractDiseasedHand(EntityUid uid, DiseasedComponent component, InteractHandEvent args)
|
||||||
|
{
|
||||||
|
if (!_interactionSystem.InRangeUnobstructed(args.User, args.Target))
|
||||||
|
return;
|
||||||
|
InteractWithDiseased (args.Target, args.User);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when someone interacts with a diseased person with any object
|
||||||
|
/// to check if they get infected
|
||||||
|
/// </summary>
|
||||||
|
private void OnInteractDiseasedUsing(EntityUid uid, DiseasedComponent component, InteractUsingEvent args)
|
||||||
|
{
|
||||||
|
InteractWithDiseased(args.Target, args.User);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when a vaccine is used on someone
|
||||||
|
/// to handle the vaccination doafter
|
||||||
|
/// </summary>
|
||||||
|
private void OnAfterInteract(EntityUid uid, DiseaseVaccineComponent vaxx, AfterInteractEvent args)
|
||||||
|
{
|
||||||
|
if (vaxx.CancelToken != null)
|
||||||
|
{
|
||||||
|
vaxx.CancelToken.Cancel();
|
||||||
|
vaxx.CancelToken = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (args.Target == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!args.CanReach)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (vaxx.CancelToken != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp<DiseaseCarrierComponent>(args.Target, out var carrier))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (vaxx.Used)
|
||||||
|
{
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("vaxx-already-used"), args.User, Filter.Entities(args.User));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vaxx.CancelToken = new CancellationTokenSource();
|
||||||
|
_doAfterSystem.DoAfter(new DoAfterEventArgs(args.User, vaxx.InjectDelay, vaxx.CancelToken.Token, target: args.Target)
|
||||||
|
{
|
||||||
|
BroadcastFinishedEvent = new TargetVaxxSuccessfulEvent(args.User, args.Target, vaxx, carrier),
|
||||||
|
BroadcastCancelledEvent = new VaxxCancelledEvent(vaxx),
|
||||||
|
BreakOnTargetMove = true,
|
||||||
|
BreakOnUserMove = true,
|
||||||
|
BreakOnStun = true,
|
||||||
|
NeedHand = true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when a vaccine is examined.
|
||||||
|
/// Currently doesn't do much because
|
||||||
|
/// vaccines don't have unique art with a seperate
|
||||||
|
/// state visualizer.
|
||||||
|
/// </summary>
|
||||||
|
private void OnExamined(EntityUid uid, DiseaseVaccineComponent vaxx, ExaminedEvent args)
|
||||||
|
{
|
||||||
|
if (args.IsInDetailsRange)
|
||||||
|
{
|
||||||
|
if (vaxx.Used)
|
||||||
|
args.PushMarkup(Loc.GetString("vaxx-used"));
|
||||||
|
else
|
||||||
|
args.PushMarkup(Loc.GetString("vaxx-unused"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Helper functions
|
||||||
|
///
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to infect anyone that
|
||||||
|
/// interacts with a diseased person or body
|
||||||
|
/// </summary>
|
||||||
|
private void InteractWithDiseased(EntityUid diseased, EntityUid target)
|
||||||
|
{
|
||||||
|
if (!TryComp<DiseaseCarrierComponent>(target, out var carrier))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var disease = _random.Pick(Comp<DiseaseCarrierComponent>(diseased).Diseases);
|
||||||
|
if (disease != null)
|
||||||
|
TryInfect(carrier, disease, 0.4f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a disease to a target
|
||||||
|
/// if it's not already in their current
|
||||||
|
/// or past diseases. If you want this
|
||||||
|
/// to not be guaranteed you are looking
|
||||||
|
/// for TryInfect.
|
||||||
|
/// </summary>
|
||||||
|
public void TryAddDisease(DiseaseCarrierComponent? target, DiseasePrototype? addedDisease, string? diseaseName = null, EntityUid host = default!)
|
||||||
|
{
|
||||||
|
if (diseaseName != null && _prototypeManager.TryIndex(diseaseName, out DiseasePrototype? diseaseProto))
|
||||||
|
addedDisease = diseaseProto;
|
||||||
|
|
||||||
|
if (host != default!)
|
||||||
|
target = Comp<DiseaseCarrierComponent>(host);
|
||||||
|
|
||||||
|
if (target != null)
|
||||||
|
{
|
||||||
|
foreach (var disease in target.AllDiseases)
|
||||||
|
{
|
||||||
|
if (disease.ID == addedDisease?.ID) //ID because of the way protoypes work
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var freshDisease = _serializationManager.CreateCopy(addedDisease) ?? default!;
|
||||||
|
target.Diseases.Add(freshDisease);
|
||||||
|
AddQueue.Enqueue(target.Owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pits the infection chance against the
|
||||||
|
/// person's disease resistance and
|
||||||
|
/// rolls the dice to see if they get
|
||||||
|
/// the disease.
|
||||||
|
/// </summary>
|
||||||
|
public void TryInfect(DiseaseCarrierComponent carrier, DiseasePrototype? disease, float chance = 0.7f)
|
||||||
|
{
|
||||||
|
if(disease == null || !disease.Infectious)
|
||||||
|
return;
|
||||||
|
var infectionChance = chance - carrier.DiseaseResist;
|
||||||
|
if (infectionChance <= 0)
|
||||||
|
return;
|
||||||
|
if (_random.Prob(infectionChance))
|
||||||
|
TryAddDisease(carrier, disease);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Plays a sneeze/cough popup if applicable
|
||||||
|
/// and then tries to infect anyone in range
|
||||||
|
/// if the snougher is not wearing a mask.
|
||||||
|
/// </summary>
|
||||||
|
public void SneezeCough(EntityUid uid, DiseasePrototype? disease, string snoughMessage, bool airTransmit = true, float infectionChance = 0.3f)
|
||||||
|
{
|
||||||
|
var xform = Comp<TransformComponent>(uid);
|
||||||
|
if (snoughMessage != string.Empty)
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString(snoughMessage, ("person", uid)), uid, Filter.Pvs(uid));
|
||||||
|
|
||||||
|
if (disease == null || !disease.Infectious || airTransmit == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_inventorySystem.TryGetSlotEntity(uid, "mask", out var maskUid) &&
|
||||||
|
EntityManager.TryGetComponent<IngestionBlockerComponent>(maskUid, out var blocker) &&
|
||||||
|
blocker.Enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var entity in _lookup.GetEntitiesInRange(xform.MapID, xform.WorldPosition, 2f))
|
||||||
|
{
|
||||||
|
if (!_interactionSystem.InRangeUnobstructed(uid, entity))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (TryComp<DiseaseCarrierComponent>(entity, out var carrier))
|
||||||
|
TryInfect(carrier, disease, 0.3f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a disease to the carrier's
|
||||||
|
/// past diseases to give them immunity
|
||||||
|
/// IF they don't already have the disease.
|
||||||
|
/// <summary>
|
||||||
|
public void Vaccinate(DiseaseCarrierComponent carrier, DiseasePrototype disease)
|
||||||
|
{
|
||||||
|
foreach (var currentDisease in carrier.Diseases)
|
||||||
|
{
|
||||||
|
if (currentDisease.ID == disease.ID) //ID because of the way protoypes work
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
carrier.PastDiseases.Add(disease);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Private Events Stuff
|
||||||
|
///
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Injects the vaccine into the target
|
||||||
|
/// if the doafter is completed
|
||||||
|
/// </summary>
|
||||||
|
private void OnTargetVaxxSuccessful(TargetVaxxSuccessfulEvent args)
|
||||||
|
{
|
||||||
|
if (args.Vaxx.Disease == null)
|
||||||
|
return;
|
||||||
|
Vaccinate(args.Carrier, args.Vaxx.Disease);
|
||||||
|
EntityManager.DeleteEntity(args.Vaxx.Owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancels the vaccine doafter
|
||||||
|
/// </summary>
|
||||||
|
private static void OnVaxxCancelled(VaxxCancelledEvent args)
|
||||||
|
{
|
||||||
|
args.Vaxx.CancelToken = null;
|
||||||
|
}
|
||||||
|
/// These two are standard doafter stuff you can ignore
|
||||||
|
private sealed class VaxxCancelledEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public readonly DiseaseVaccineComponent Vaxx;
|
||||||
|
public VaxxCancelledEvent(DiseaseVaccineComponent vaxx)
|
||||||
|
{
|
||||||
|
Vaxx = vaxx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private sealed class TargetVaxxSuccessfulEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public EntityUid User { get; }
|
||||||
|
public EntityUid? Target { get; }
|
||||||
|
public DiseaseVaccineComponent Vaxx { get; }
|
||||||
|
public DiseaseCarrierComponent Carrier { get; }
|
||||||
|
public TargetVaxxSuccessfulEvent(EntityUid user, EntityUid? target, DiseaseVaccineComponent vaxx, DiseaseCarrierComponent carrier)
|
||||||
|
{
|
||||||
|
User = user;
|
||||||
|
Target = target;
|
||||||
|
Vaxx = vaxx;
|
||||||
|
Carrier = carrier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This event is fired by chems
|
||||||
|
/// and other brute-force rather than
|
||||||
|
/// specific cures. It will roll the dice to attempt
|
||||||
|
/// to cure each disease on the target
|
||||||
|
/// </summary>
|
||||||
|
public sealed class CureDiseaseAttemptEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public float CureChance { get; }
|
||||||
|
public CureDiseaseAttemptEvent(float cureChance)
|
||||||
|
{
|
||||||
|
CureChance = cureChance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Controls whether the snough is a sneeze, cough
|
||||||
|
/// or neither. If none, will not create
|
||||||
|
/// a popup. Mostly used for talking
|
||||||
|
/// </summary>
|
||||||
|
public enum SneezeCoughType
|
||||||
|
{
|
||||||
|
Sneeze,
|
||||||
|
Cough,
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
46
Content.Server/Disease/Effects/DiseaseAdjustReagent.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using Content.Server.Chemistry.EntitySystems;
|
||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
|
using Content.Shared.FixedPoint;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Content.Server.Body.Components;
|
||||||
|
using Content.Shared.Disease;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
|
namespace Content.Server.Disease.Effects
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds or removes reagents from the
|
||||||
|
/// host's chemstream.
|
||||||
|
/// </summary>
|
||||||
|
[UsedImplicitly]
|
||||||
|
public sealed class DiseaseAdjustReagent : DiseaseEffect
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The reagent ID to add or remove.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("reagent", customTypeSerializer:typeof(PrototypeIdSerializer<ReagentPrototype>))]
|
||||||
|
public string? Reagent = null;
|
||||||
|
|
||||||
|
[DataField("amount", required: true)]
|
||||||
|
public FixedPoint2 Amount = default!;
|
||||||
|
|
||||||
|
public override void Effect(DiseaseEffectArgs args)
|
||||||
|
{
|
||||||
|
if (!args.EntityManager.TryGetComponent<BloodstreamComponent>(args.DiseasedEntity, out var bloodstream))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var stream = bloodstream.ChemicalSolution;
|
||||||
|
if (stream != null)
|
||||||
|
{
|
||||||
|
var solutionSys = args.EntityManager.EntitySysManager.GetEntitySystem<SolutionContainerSystem>();
|
||||||
|
if (Reagent != null)
|
||||||
|
{
|
||||||
|
if (Amount < 0 && stream.ContainsReagent(Reagent))
|
||||||
|
solutionSys.TryRemoveReagent(args.DiseasedEntity, stream, Reagent, -Amount);
|
||||||
|
if (Amount > 0)
|
||||||
|
solutionSys.TryAddReagent(args.DiseasedEntity, stream, Reagent, Amount, out _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
67
Content.Server/Disease/Effects/DiseaseGenericStatusEffect.cs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
using Content.Shared.Disease;
|
||||||
|
using Content.Shared.StatusEffect;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
|
namespace Content.Server.Disease.Effects
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a generic status effect to the entity.
|
||||||
|
/// Differs from the chem version in its defaults
|
||||||
|
/// to better facilitate adding components that
|
||||||
|
/// last the length of the disease.
|
||||||
|
/// </summary>
|
||||||
|
[UsedImplicitly]
|
||||||
|
public sealed class DiseaseGenericStatusEffect : DiseaseEffect
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The status effect key
|
||||||
|
/// Prevents other components from being with the same key
|
||||||
|
/// </summary>
|
||||||
|
[DataField("key", required: true)]
|
||||||
|
public string Key = default!;
|
||||||
|
/// <summary>
|
||||||
|
/// The component to add
|
||||||
|
/// </summary>
|
||||||
|
[DataField("component")]
|
||||||
|
public string Component = String.Empty;
|
||||||
|
|
||||||
|
[DataField("time")]
|
||||||
|
public float Time = 1.01f; /// I'm afraid if this was exact the key could get stolen by another thing
|
||||||
|
|
||||||
|
/// <remarks>
|
||||||
|
/// true - refresh status effect time, false - accumulate status effect time
|
||||||
|
/// </remarks>
|
||||||
|
[DataField("refresh")]
|
||||||
|
public bool Refresh = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Should this effect add the status effect, remove time from it, or set its cooldown?
|
||||||
|
/// </summary>
|
||||||
|
[DataField("type")]
|
||||||
|
public StatusEffectDiseaseType Type = StatusEffectDiseaseType.Add;
|
||||||
|
|
||||||
|
public override void Effect(DiseaseEffectArgs args)
|
||||||
|
{
|
||||||
|
var statusSys = EntitySystem.Get<StatusEffectsSystem>();
|
||||||
|
if (Type == StatusEffectDiseaseType.Add && Component != String.Empty)
|
||||||
|
{
|
||||||
|
statusSys.TryAddStatusEffect(args.DiseasedEntity, Key, TimeSpan.FromSeconds(Time), Refresh, Component);
|
||||||
|
}
|
||||||
|
else if (Type == StatusEffectDiseaseType.Remove)
|
||||||
|
{
|
||||||
|
statusSys.TryRemoveTime(args.DiseasedEntity, Key, TimeSpan.FromSeconds(Time));
|
||||||
|
}
|
||||||
|
else if (Type == StatusEffectDiseaseType.Set)
|
||||||
|
{
|
||||||
|
statusSys.TrySetTime(args.DiseasedEntity, Key, TimeSpan.FromSeconds(Time));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// See status effects for how these work
|
||||||
|
public enum StatusEffectDiseaseType
|
||||||
|
{
|
||||||
|
Add,
|
||||||
|
Remove,
|
||||||
|
Set
|
||||||
|
}
|
||||||
|
}
|
||||||
21
Content.Server/Disease/Effects/DiseaseHealthChange.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using Content.Shared.Disease;
|
||||||
|
using Content.Shared.Damage;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
|
namespace Content.Server.Disease.Effects
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Deals or heals damage to the host
|
||||||
|
/// </summary>
|
||||||
|
[UsedImplicitly]
|
||||||
|
public sealed class DiseaseHealthChange : DiseaseEffect
|
||||||
|
{
|
||||||
|
[DataField("damage", required: true)]
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public DamageSpecifier Damage = default!;
|
||||||
|
public override void Effect(DiseaseEffectArgs args)
|
||||||
|
{
|
||||||
|
EntitySystem.Get<DamageableSystem>().TryChangeDamage(args.DiseasedEntity, Damage, true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
Content.Server/Disease/Effects/DiseasePopUp.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using Content.Shared.Disease;
|
||||||
|
using Content.Shared.Popups;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
|
namespace Content.Server.Disease.Effects
|
||||||
|
{
|
||||||
|
[UsedImplicitly]
|
||||||
|
/// <summary>
|
||||||
|
/// Plays a popup on the host's transform.
|
||||||
|
/// Supports passing the host's entity metadata
|
||||||
|
/// in PVS ones with {$person}
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DiseasePopUp : DiseaseEffect
|
||||||
|
{
|
||||||
|
[DataField("message")]
|
||||||
|
public string Message = "disease-sick-generic";
|
||||||
|
|
||||||
|
[DataField("type")]
|
||||||
|
public PopupType Type = PopupType.Local;
|
||||||
|
public override void Effect(DiseaseEffectArgs args)
|
||||||
|
{
|
||||||
|
var popupSys = EntitySystem.Get<SharedPopupSystem>();
|
||||||
|
|
||||||
|
if (Type == PopupType.Local)
|
||||||
|
popupSys.PopupEntity(Loc.GetString(Message), args.DiseasedEntity, Filter.Entities(args.DiseasedEntity));
|
||||||
|
else if (Type == PopupType.Pvs)
|
||||||
|
popupSys.PopupEntity(Loc.GetString(Message, ("person", args.DiseasedEntity)), args.DiseasedEntity, Filter.Pvs(args.DiseasedEntity));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PopupType
|
||||||
|
{
|
||||||
|
Pvs,
|
||||||
|
Local
|
||||||
|
}
|
||||||
|
}
|
||||||
30
Content.Server/Disease/Effects/DiseaseSnough.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using Content.Shared.Disease;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
|
namespace Content.Server.Disease
|
||||||
|
{
|
||||||
|
[UsedImplicitly]
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Makes the diseased sneeze or cough
|
||||||
|
/// or neither.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DiseaseSnough : DiseaseEffect
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Message to play when snoughing
|
||||||
|
/// </summary>
|
||||||
|
[DataField("snoughMessage")]
|
||||||
|
public string SnoughMessage = "disease-sneeze";
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to spread the disease throught he air
|
||||||
|
/// </summary>
|
||||||
|
[DataField("airTransmit")]
|
||||||
|
public bool AirTransmit = true;
|
||||||
|
|
||||||
|
public override void Effect(DiseaseEffectArgs args)
|
||||||
|
{
|
||||||
|
EntitySystem.Get<DiseaseSystem>().SneezeCough(args.DiseasedEntity, args.Disease, SnoughMessage, AirTransmit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ namespace Content.Server.Entry
|
|||||||
"ClientEntitySpawner",
|
"ClientEntitySpawner",
|
||||||
"CharacterInfo",
|
"CharacterInfo",
|
||||||
"ItemCabinetVisuals",
|
"ItemCabinetVisuals",
|
||||||
|
"DiseaseMachineVisuals",
|
||||||
"HandheldGPS",
|
"HandheldGPS",
|
||||||
"PotencyVisuals"
|
"PotencyVisuals"
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Content.Server.UserInterface;
|
using Content.Server.UserInterface;
|
||||||
using Content.Shared.MedicalScanner;
|
using Content.Shared.MedicalScanner;
|
||||||
|
using Content.Shared.Disease;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
namespace Content.Server.Medical.Components
|
namespace Content.Server.Medical.Components
|
||||||
{
|
{
|
||||||
@@ -23,5 +25,19 @@ namespace Content.Server.Medical.Components
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public CancellationTokenSource? CancelToken;
|
public CancellationTokenSource? CancelToken;
|
||||||
public BoundUserInterface? UserInterface => Owner.GetUIOrNull(HealthAnalyzerUiKey.Key);
|
public BoundUserInterface? UserInterface => Owner.GetUIOrNull(HealthAnalyzerUiKey.Key);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is this actually going to give people the disease below
|
||||||
|
/// </summary>
|
||||||
|
[DataField("fake")]
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public bool Fake = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The disease this will give people if Fake == true
|
||||||
|
/// </summary>
|
||||||
|
[DataField("disease", customTypeSerializer: typeof(PrototypeIdSerializer<DiseasePrototype>))]
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public string Disease = string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Content.Server.DoAfter;
|
using Content.Server.DoAfter;
|
||||||
using Content.Server.Medical.Components;
|
using Content.Server.Medical.Components;
|
||||||
|
using Content.Server.Disease;
|
||||||
|
using Content.Server.Popups;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.MobState.Components;
|
using Content.Shared.MobState.Components;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Shared.Player;
|
||||||
using static Content.Shared.MedicalScanner.SharedHealthAnalyzerComponent;
|
using static Content.Shared.MedicalScanner.SharedHealthAnalyzerComponent;
|
||||||
|
|
||||||
namespace Content.Server.Medical
|
namespace Content.Server.Medical
|
||||||
@@ -12,6 +15,7 @@ namespace Content.Server.Medical
|
|||||||
public sealed class HealthAnalyzerSystem : EntitySystem
|
public sealed class HealthAnalyzerSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
||||||
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -64,6 +68,22 @@ namespace Content.Server.Medical
|
|||||||
{
|
{
|
||||||
args.Component.CancelToken = null;
|
args.Component.CancelToken = null;
|
||||||
UpdateScannedUser(args.Component.Owner, args.User, args.Target, args.Component);
|
UpdateScannedUser(args.Component.Owner, args.User, args.Target, args.Component);
|
||||||
|
/// Below is for the traitor item
|
||||||
|
/// Piggybacking off another component's doafter is complete CBT so I gave up
|
||||||
|
/// and put it on the same component
|
||||||
|
if (!args.Component.Fake || args.Component.Disease == string.Empty || args.Target == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
EntitySystem.Get<DiseaseSystem>().TryAddDisease(null, null, args.Component.Disease, args.Target.Value);
|
||||||
|
|
||||||
|
if (args.User == args.Target)
|
||||||
|
{
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("disease-scanner-gave-self", ("disease", args.Component.Disease)),
|
||||||
|
args.User, Filter.Entities(args.User));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("disease-scanner-gave-other", ("target", args.Target), ("disease", args.Component.Disease)),
|
||||||
|
args.User, Filter.Entities(args.User));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OpenUserInterface(EntityUid user, HealthAnalyzerComponent healthAnalyzer)
|
private void OpenUserInterface(EntityUid user, HealthAnalyzerComponent healthAnalyzer)
|
||||||
|
|||||||
62
Content.Server/StationEvents/Events/DiseaseOutbreak.cs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using Content.Server.Chat.Managers;
|
||||||
|
using Content.Server.Disease.Components;
|
||||||
|
using Content.Server.Disease;
|
||||||
|
using Content.Shared.Disease;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Server.StationEvents.Events;
|
||||||
|
/// <summary>
|
||||||
|
/// Infects a couple people
|
||||||
|
/// with a random disease that isn't super deadly
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DiseaseOutbreak : StationEvent
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disease prototypes I decided were not too deadly for a random event
|
||||||
|
/// </summary>
|
||||||
|
public readonly IReadOnlyList<string> NotTooSeriousDiseases = new[]
|
||||||
|
{
|
||||||
|
"SpaceCold",
|
||||||
|
"VanAusdallsRobovirus",
|
||||||
|
"VentCough",
|
||||||
|
"AMIV"
|
||||||
|
};
|
||||||
|
public override string Name => "DiseaseOutbreak";
|
||||||
|
public override float Weight => WeightNormal;
|
||||||
|
protected override float EndAfter => 1.0f;
|
||||||
|
/// <summary>
|
||||||
|
/// Finds 2-5 random entities that can host diseases
|
||||||
|
/// and gives them a randomly selected disease.
|
||||||
|
/// They all get the same disease.
|
||||||
|
/// </summary>
|
||||||
|
public override void Startup()
|
||||||
|
{
|
||||||
|
base.Startup();
|
||||||
|
|
||||||
|
var targetList = _entityManager.EntityQuery<DiseaseCarrierComponent>().ToList();
|
||||||
|
_random.Shuffle(targetList);
|
||||||
|
|
||||||
|
var toInfect = _random.Next(2, 5);
|
||||||
|
|
||||||
|
var diseaseName = _random.Pick(NotTooSeriousDiseases);
|
||||||
|
|
||||||
|
if (!_prototypeManager.TryIndex(diseaseName, out DiseasePrototype? disease) || disease == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var target in targetList)
|
||||||
|
{
|
||||||
|
if (toInfect-- == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
EntitySystem.Get<DiseaseSystem>().TryAddDisease(target, disease);
|
||||||
|
}
|
||||||
|
_chatManager.DispatchStationAnnouncement(Loc.GetString("station-event-disease-outbreak-announcement"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,7 +42,7 @@ public sealed class VentClog : StationEvent
|
|||||||
public readonly IReadOnlyList<string> SafeishVentChemicals = new[]
|
public readonly IReadOnlyList<string> SafeishVentChemicals = new[]
|
||||||
{
|
{
|
||||||
"Water", "Iron", "Oxygen", "Tritium", "Plasma", "SulfuricAcid", "Blood", "SpaceDrugs", "SpaceCleaner", "Flour",
|
"Water", "Iron", "Oxygen", "Tritium", "Plasma", "SulfuricAcid", "Blood", "SpaceDrugs", "SpaceCleaner", "Flour",
|
||||||
"Nutriment", "Sugar", "SpaceLube", "Ethanol", "Mercury", "Ephedrine", "WeldingFuel"
|
"Nutriment", "Sugar", "SpaceLube", "Ethanol", "Mercury", "Ephedrine", "WeldingFuel", "VentCrud"
|
||||||
};
|
};
|
||||||
|
|
||||||
public override void Startup()
|
public override void Startup()
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
using Content.Shared.Disease;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
|
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;
|
||||||
|
/// <summary>
|
||||||
|
/// Spawn a random disease at regular intervals when artifact activated.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class DiseaseArtifactComponent : Component
|
||||||
|
{
|
||||||
|
public override string Name => "DiseaseArtifact";
|
||||||
|
/// <summary>
|
||||||
|
/// Disease the artifact will spawn
|
||||||
|
/// If empty, picks a random one from its list
|
||||||
|
/// </summary>
|
||||||
|
[DataField("disease", customTypeSerializer: typeof(PrototypeIdSerializer<DiseasePrototype>))]
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public string SpawnDisease = string.Empty;
|
||||||
|
/// <summary>
|
||||||
|
/// How far away it will check for people
|
||||||
|
/// If empty, picks a random one from its list
|
||||||
|
/// </summary>
|
||||||
|
[DataField("range")]
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float Range = 5f;
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public DiseasePrototype ResolveDisease = default!;
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public readonly IReadOnlyList<string> ArtifactDiseases = new[]
|
||||||
|
{
|
||||||
|
"VanAusdallsRobovirus",
|
||||||
|
"OwOnavirus",
|
||||||
|
"BleedersBite",
|
||||||
|
"Ultragigacancer",
|
||||||
|
"AMIV"
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
|
||||||
|
using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;
|
||||||
|
using Content.Shared.Disease;
|
||||||
|
using Content.Server.Disease;
|
||||||
|
using Content.Server.Disease.Components;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
|
||||||
|
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Handles disease-producing artifacts
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DiseaseArtifactSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
SubscribeLocalEvent<DiseaseArtifactComponent, MapInitEvent>(OnMapInit);
|
||||||
|
SubscribeLocalEvent<DiseaseArtifactComponent, ArtifactActivatedEvent>(OnActivate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Makes sure this artifact is assigned a disease
|
||||||
|
/// </summary>
|
||||||
|
private void OnMapInit(EntityUid uid, DiseaseArtifactComponent component, MapInitEvent args)
|
||||||
|
{
|
||||||
|
if (component.SpawnDisease == string.Empty && component.ArtifactDiseases.Count != 0)
|
||||||
|
{
|
||||||
|
var diseaseName = _random.Pick(component.ArtifactDiseases);
|
||||||
|
|
||||||
|
component.SpawnDisease = diseaseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_prototypeManager.TryIndex(component.SpawnDisease, out DiseasePrototype? disease) && disease != null)
|
||||||
|
component.ResolveDisease = disease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When activated, blasts everyone in LOS within 3 tiles
|
||||||
|
/// with a high-probability disease infection attempt
|
||||||
|
/// </summary>
|
||||||
|
private void OnActivate(EntityUid uid, DiseaseArtifactComponent component, ArtifactActivatedEvent args)
|
||||||
|
{
|
||||||
|
var xform = Transform(uid);
|
||||||
|
foreach (var entity in _lookup.GetEntitiesInRange(xform.MapID, xform.WorldPosition, 3f))
|
||||||
|
{
|
||||||
|
if (!_interactionSystem.InRangeUnobstructed(uid, entity, 3f))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (TryComp<DiseaseCarrierComponent>(entity, out var carrier))
|
||||||
|
EntitySystem.Get<DiseaseSystem>().TryInfect(carrier, component.ResolveDisease);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
|
||||||
|
|
||||||
namespace Content.Shared.Chemistry.Reagent
|
namespace Content.Shared.Chemistry.Reagent
|
||||||
{
|
{
|
||||||
|
|||||||
24
Content.Shared/Disease/DiseaseCure.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
|
namespace Content.Shared.Disease
|
||||||
|
{
|
||||||
|
[ImplicitDataDefinitionForInheritors]
|
||||||
|
[MeansImplicitUse]
|
||||||
|
public abstract class DiseaseCure
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This returns true if the disease should be cured
|
||||||
|
/// and false otherwise
|
||||||
|
/// </summary>
|
||||||
|
public abstract bool Cure(DiseaseEffectArgs args);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is used by the disease diangoser machine
|
||||||
|
/// to generate reports to tell people all of a disease's
|
||||||
|
/// special cures using in-game methods.
|
||||||
|
/// So it should return a localization string describing
|
||||||
|
/// the cure
|
||||||
|
/// </summary>
|
||||||
|
public abstract string CureText();
|
||||||
|
}
|
||||||
|
}
|
||||||
29
Content.Shared/Disease/DiseaseEffect.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
|
namespace Content.Shared.Disease
|
||||||
|
{
|
||||||
|
[ImplicitDataDefinitionForInheritors]
|
||||||
|
[MeansImplicitUse]
|
||||||
|
public abstract class DiseaseEffect
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// What's the chance, from 0 to 1, that this effect will occur?
|
||||||
|
/// </summary>
|
||||||
|
[DataField("probability")]
|
||||||
|
public float Probability = 1.0f;
|
||||||
|
/// <summary>
|
||||||
|
/// What effect the disease will have.
|
||||||
|
/// </summary>
|
||||||
|
public abstract void Effect(DiseaseEffectArgs args);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// What you have to work with in any disease effect/cure.
|
||||||
|
/// Includes an entity manager because it is out of scope
|
||||||
|
/// otherwise.
|
||||||
|
/// </summary>
|
||||||
|
public readonly record struct DiseaseEffectArgs(
|
||||||
|
EntityUid DiseasedEntity,
|
||||||
|
DiseasePrototype Disease,
|
||||||
|
IEntityManager EntityManager
|
||||||
|
);
|
||||||
|
}
|
||||||
16
Content.Shared/Disease/DiseaseMachineVisuals.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Disease
|
||||||
|
{
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
/// <summary>
|
||||||
|
/// Stores bools for if the machine is on
|
||||||
|
/// and if it's currently running.
|
||||||
|
/// Used for the visualizer
|
||||||
|
/// </summary>
|
||||||
|
public enum DiseaseMachineVisuals : byte
|
||||||
|
{
|
||||||
|
IsOn,
|
||||||
|
IsRunning
|
||||||
|
}
|
||||||
|
}
|
||||||
68
Content.Shared/Disease/DiseasePrototype.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
/// <summary>
|
||||||
|
/// Diseases encompass everything from viruses to cancers to heart disease.
|
||||||
|
/// It's not just a virology thing.
|
||||||
|
/// </summary>
|
||||||
|
namespace Content.Shared.Disease
|
||||||
|
{
|
||||||
|
[Prototype("disease")]
|
||||||
|
[DataDefinition]
|
||||||
|
public sealed class DiseasePrototype : IPrototype, IInheritingPrototype
|
||||||
|
{
|
||||||
|
[ViewVariables]
|
||||||
|
[DataField("id", required: true)]
|
||||||
|
public string ID { get; } = default!;
|
||||||
|
|
||||||
|
[DataField("name")]
|
||||||
|
public string Name { get; } = string.Empty;
|
||||||
|
|
||||||
|
[DataField("parent", customTypeSerializer: typeof(PrototypeIdSerializer<DiseasePrototype>))]
|
||||||
|
public string? Parent { get; private set; }
|
||||||
|
|
||||||
|
[NeverPushInheritance]
|
||||||
|
[DataField("abstract")]
|
||||||
|
public bool Abstract { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Controls how often a disease ticks.
|
||||||
|
/// </summary>
|
||||||
|
public float TickTime = 1f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Since disease isn't mapped to metabolism or anything,
|
||||||
|
/// it needs something to control its tickrate
|
||||||
|
/// </summary>
|
||||||
|
public float Accumulator = 0f;
|
||||||
|
/// <summary>
|
||||||
|
/// List of effects the disease has that will
|
||||||
|
/// run every second (by default anyway)
|
||||||
|
/// </summary>
|
||||||
|
[DataField("effects", serverOnly: true)]
|
||||||
|
public readonly List<DiseaseEffect> Effects = new(0);
|
||||||
|
/// <summary>
|
||||||
|
/// List of SPECIFIC CURES the disease has that will
|
||||||
|
/// be checked every second.
|
||||||
|
/// Stuff like spaceacillin operates outside this.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("cures", serverOnly: true)]
|
||||||
|
public readonly List<DiseaseCure> Cures = new(0);
|
||||||
|
/// <summary>
|
||||||
|
/// This flatly reduces the probabilty disease medicine
|
||||||
|
/// has to cure it every tick. Although, since spaceacillin is
|
||||||
|
/// used as a reference and it has 0.15 chance, this is
|
||||||
|
/// a base 33% reduction in cure chance
|
||||||
|
/// </summary>
|
||||||
|
[DataField("cureResist", serverOnly: true)]
|
||||||
|
public float CureResist = 0.05f;
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the disease can infect other people.
|
||||||
|
/// Since this isn't just a virology thing, this
|
||||||
|
/// primary determines what sort of disease it is.
|
||||||
|
/// This also affects things like the vaccine machine.
|
||||||
|
/// You can't print a cancer vaccine
|
||||||
|
/// </summary>
|
||||||
|
[DataField("infectious", serverOnly: true)]
|
||||||
|
public bool Infectious = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
Content.Shared/Disease/DiseasedComponent.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
|
namespace Content.Shared.Disease.Components
|
||||||
|
{
|
||||||
|
[NetworkedComponent]
|
||||||
|
[RegisterComponent]
|
||||||
|
/// This is added to anyone with at least 1 disease
|
||||||
|
/// and helps cull event subscriptions and entity queries
|
||||||
|
/// when they are not relevant.
|
||||||
|
public sealed class DiseasedComponent : Component
|
||||||
|
{}
|
||||||
|
}
|
||||||
BIN
Resources/Audio/Machines/diagnoser_printing.ogg
Normal file
3
Resources/Audio/Machines/license.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
diagnoser_printing.ogg taken from https://freesound.org/people/RobSp1derp1g/sounds/615419/ and edited
|
||||||
|
|
||||||
|
vaccinator_running.ogg taken from https://freesound.org/people/RutgerMuller/sounds/365413/ and edited
|
||||||
BIN
Resources/Audio/Machines/vaccinator_running.ogg
Normal file
20
Resources/Locale/en-US/disease/diagnoser.ftl
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
diagnoser-cant-use-swab = {CAPITALIZE(THE($machine))} rejects {THE($swab)}.
|
||||||
|
diagnoser-insert-swab = You insert {THE($swab)} into {THE($machine)}.
|
||||||
|
diagnoser-disease-report = Disease Report: {CAPITALIZE($disease)}
|
||||||
|
diagnoser-disease-report-none = Bill of Good Health
|
||||||
|
diagnoser-disease-report-none-contents = [color=green]No diseases were found in this sample.[/color]
|
||||||
|
diagnoser-disease-report-name = Disease Name: {CAPITALIZE($disease)}
|
||||||
|
diagnoser-disease-report-infectious = Infectious: [color=red]Yes[/color]
|
||||||
|
diagnoser-disease-report-not-infectious = Infectious: [color=green]No[/color]
|
||||||
|
diagnoser-disease-report-cureresist-none = Medication Resistance: [color=green]None[/color]
|
||||||
|
diagnoser-disease-report-cureresist-low = Medication Resistance: [color=yellow]Low[/color]
|
||||||
|
diagnoser-disease-report-cureresist-medium = Medication Resistance: [color=orange]Medium[/color]
|
||||||
|
diagnoser-disease-report-cureresist-high = Medication 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-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.
|
||||||
|
diagnoser-cure-temp-min = Reach a body temperature above {$min}°K.
|
||||||
|
diagnoser-cure-temp-max = Reach a body temperature below {$max}°K.
|
||||||
10
Resources/Locale/en-US/disease/disease.ftl
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
disease-cured = You feel a bit better.
|
||||||
|
disease-sick-generic = You feel sick.
|
||||||
|
disease-sneeze = {CAPITALIZE($person)} sneezes.
|
||||||
|
disease-cough = {CAPITALIZE($person)} coughs.
|
||||||
|
disease-screech = {CAPITALIZE($person)} screeches.
|
||||||
|
disease-meow = {CAPITALIZE($person)} meows.
|
||||||
|
disease-beep= {CAPITALIZE($person)} beeps.
|
||||||
|
disease-eaten-inside = You feel like you're being eaten from the inside.
|
||||||
|
disease-steal-compulsion = You want to steal things.
|
||||||
|
disease-beat-chest-compulsion = {CAPITALIZE(THE($person))} beats {POSS-ADJ($person)} chest.
|
||||||
4
Resources/Locale/en-US/disease/scanner.ftl
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
disease-scanner-diseased = DISEASED
|
||||||
|
disease-scanner-not-diseased = No diseases
|
||||||
|
disease-scanner-gave-other = You gave {THE($target)} {CAPITALIZE($disease)}!
|
||||||
|
disease-scanner-gave-self = You gave yourself {CAPITALIZE($disease)}! Congratulations!
|
||||||
5
Resources/Locale/en-US/disease/swab.ftl
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
swab-already-used = You already used this swab.
|
||||||
|
swab-swabbed = You swab {THE($target)}'s mouth.
|
||||||
|
swab-mask-blocked = {CAPITALIZE(THE($target))} needs to take off {THE($mask)}.
|
||||||
|
swab-used = It looks like it's been used.
|
||||||
|
swab-unused = It's clean and ready to use.
|
||||||
3
Resources/Locale/en-US/disease/vaccine.ftl
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
vaxx-already-used = You already used this vaccine.
|
||||||
|
vaxx-used = It's spent.
|
||||||
|
vaxx-unused = It hasn't been spent.
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
station-event-disease-outbreak-announcement = Ship systems have detected that some crewmates have been infected with a disease.
|
||||||
@@ -58,6 +58,16 @@
|
|||||||
- state: box
|
- state: box
|
||||||
- state: latex
|
- state: latex
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
name: mouth swab box
|
||||||
|
parent: BoxCardboard
|
||||||
|
id: BoxMouthSwab
|
||||||
|
components:
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: DiseaseSwab
|
||||||
|
amount: 30
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: body bag box
|
name: body bag box
|
||||||
parent: BoxCardboard
|
parent: BoxCardboard
|
||||||
|
|||||||
@@ -19,6 +19,12 @@
|
|||||||
amount: 2
|
amount: 2
|
||||||
- id: Gauze
|
- id: Gauze
|
||||||
amount: 2
|
amount: 2
|
||||||
|
- id: BoxLatex
|
||||||
|
amount: 1
|
||||||
|
- id: BoxSterile
|
||||||
|
amount: 1
|
||||||
|
- id: BoxMouthSwab
|
||||||
|
amount: 1
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: CrateChemistrySupplies
|
id: CrateChemistrySupplies
|
||||||
|
|||||||
@@ -50,6 +50,8 @@
|
|||||||
components:
|
components:
|
||||||
- type: StorageFill
|
- type: StorageFill
|
||||||
contents:
|
contents:
|
||||||
|
- id: SyringeSpaceacillin
|
||||||
|
amount: 1
|
||||||
- id: PillDylovene
|
- id: PillDylovene
|
||||||
amount: 3
|
amount: 3
|
||||||
|
|
||||||
|
|||||||
@@ -129,7 +129,7 @@
|
|||||||
- type: StorageFill
|
- type: StorageFill
|
||||||
contents:
|
contents:
|
||||||
- id: MedkitFilled
|
- id: MedkitFilled
|
||||||
- id: ClothingHandsGlovesLatex
|
- id: ClothingHandsGlovesNitrile
|
||||||
#- name: ClothingEyesHudMedical #Removed until working properly
|
#- name: ClothingEyesHudMedical #Removed until working properly
|
||||||
# prob: 1
|
# prob: 1
|
||||||
- id: ClothingHeadsetAltMedical
|
- id: ClothingHeadsetAltMedical
|
||||||
@@ -139,6 +139,9 @@
|
|||||||
- id: ClothingMaskSterile
|
- id: ClothingMaskSterile
|
||||||
- id: ClothingHeadHelmetHardsuitMedical
|
- id: ClothingHeadHelmetHardsuitMedical
|
||||||
- id: ClothingOuterHardsuitMedical
|
- id: ClothingOuterHardsuitMedical
|
||||||
|
- id: DiagnoserMachineCircuitboard
|
||||||
|
- id: VaccinatorMachineCircuitboard
|
||||||
|
prob: 0.25
|
||||||
- id: Hypospray
|
- id: Hypospray
|
||||||
- id: HandheldCrewMonitor
|
- id: HandheldCrewMonitor
|
||||||
- id: DoorRemoteMedical
|
- id: DoorRemoteMedical
|
||||||
|
|||||||
@@ -116,6 +116,8 @@
|
|||||||
- ChemMasterMachineCircuitboard
|
- ChemMasterMachineCircuitboard
|
||||||
- ChemDispenserMachineCircuitboard
|
- ChemDispenserMachineCircuitboard
|
||||||
- CrewMonitoringComputerCircuitboard
|
- CrewMonitoringComputerCircuitboard
|
||||||
|
- VaccinatorMachineCircuitboard
|
||||||
|
- DiagnoserMachineCircuitboard
|
||||||
- HandheldCrewMonitor
|
- HandheldCrewMonitor
|
||||||
|
|
||||||
# Security Technology Tree
|
# Security Technology Tree
|
||||||
|
|||||||
@@ -284,3 +284,11 @@
|
|||||||
category: Misc
|
category: Misc
|
||||||
itemId: ClothingBackpackDuffelSyndicatePyjamaBundle
|
itemId: ClothingBackpackDuffelSyndicatePyjamaBundle
|
||||||
price: 4
|
price: 4
|
||||||
|
|
||||||
|
- type: uplinkListing
|
||||||
|
id: UplinkGigacancerScanner
|
||||||
|
category: Misc
|
||||||
|
itemId: HandheldHealthAnalyzerGigacancer
|
||||||
|
listingName: Ultragigacancer Health Analyzer
|
||||||
|
description: Works like a normal health analyzer, other than giving everyone it scans ultragigacancer.
|
||||||
|
price: 5
|
||||||
|
|||||||
@@ -83,6 +83,15 @@
|
|||||||
Cold: 1.5
|
Cold: 1.5
|
||||||
Poison: 0.8
|
Poison: 0.8
|
||||||
|
|
||||||
|
- type: damageModifierSet
|
||||||
|
id: Scale # Skin tougher, bones weaker, strong stomachs, cold-blooded (kindof)
|
||||||
|
coefficients:
|
||||||
|
Blunt: 1.1
|
||||||
|
Slash: 0.9
|
||||||
|
Cold: 1.5
|
||||||
|
Heat: 0.9
|
||||||
|
Poison: 0.9
|
||||||
|
|
||||||
# Represents which damage types should be modified
|
# Represents which damage types should be modified
|
||||||
# in relation to how they cause bloodloss damage.
|
# in relation to how they cause bloodloss damage.
|
||||||
- type: damageModifierSet
|
- type: damageModifierSet
|
||||||
|
|||||||
138
Resources/Prototypes/Diseases/infectious.yml
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
- type: disease
|
||||||
|
id: SpaceCold
|
||||||
|
name: space cold
|
||||||
|
cureResist: 0
|
||||||
|
effects:
|
||||||
|
- !type:DiseaseAdjustReagent
|
||||||
|
probability: 0.2
|
||||||
|
reagent: Histamine
|
||||||
|
amount: 0.5
|
||||||
|
- !type:DiseasePopUp
|
||||||
|
probability: 0.025
|
||||||
|
- !type:DiseaseSnough
|
||||||
|
probability: 0.025
|
||||||
|
cures:
|
||||||
|
- !type:DiseaseBedrestCure
|
||||||
|
maxLength: 20
|
||||||
|
- !type:DiseaseJustWaitCure
|
||||||
|
maxLength: 400
|
||||||
|
- !type:DiseaseReagentCure
|
||||||
|
reagent: Ultravasculine
|
||||||
|
### - !type:DiseaseReagentCure ### In Loving Memory, Lean
|
||||||
|
### reagent: Lean ### 2022/03/12 - 2022/03/13
|
||||||
|
|
||||||
|
- type: disease
|
||||||
|
id: VentCough
|
||||||
|
name: vent cough
|
||||||
|
effects:
|
||||||
|
- !type:DiseasePopUp
|
||||||
|
probability: 0.025
|
||||||
|
message: burning-insides
|
||||||
|
- !type:DiseaseSnough
|
||||||
|
probability: 0.025
|
||||||
|
snoughMessage: disease-cough
|
||||||
|
- !type:DiseaseHealthChange
|
||||||
|
probability: 0.015
|
||||||
|
damage:
|
||||||
|
groups:
|
||||||
|
Caustic: 1
|
||||||
|
cures:
|
||||||
|
- !type:DiseaseBedrestCure
|
||||||
|
maxLength: 30
|
||||||
|
- !type:DiseaseJustWaitCure
|
||||||
|
maxLength: 600
|
||||||
|
- !type:DiseaseReagentCure
|
||||||
|
reagent: SpaceCleaner
|
||||||
|
|
||||||
|
- type: disease
|
||||||
|
id: VanAusdallsRobovirus
|
||||||
|
name: Van Ausdall's Robovirus
|
||||||
|
cureResist: 0.1
|
||||||
|
effects:
|
||||||
|
- !type:DiseaseAdjustReagent
|
||||||
|
probability: 0.025
|
||||||
|
reagent: Licoxide
|
||||||
|
amount: 0.5
|
||||||
|
- !type:DiseaseSnough
|
||||||
|
probability: 0.02
|
||||||
|
snoughMessage: disease-beep
|
||||||
|
cures:
|
||||||
|
- !type:DiseaseJustWaitCure
|
||||||
|
maxLength: 900
|
||||||
|
- !type:DiseaseReagentCure
|
||||||
|
reagent: BeepskySmash
|
||||||
|
|
||||||
|
- type: disease
|
||||||
|
id: AMIV
|
||||||
|
name: AMIV
|
||||||
|
cureResist: 0.10
|
||||||
|
effects:
|
||||||
|
- !type:DiseasePopUp
|
||||||
|
probability: 0.015
|
||||||
|
type: Pvs
|
||||||
|
message: disease-beat-chest-compulsion
|
||||||
|
- !type:DiseasePopUp
|
||||||
|
probability: 0.03
|
||||||
|
message: disease-steal-compulsion
|
||||||
|
- !type:DiseaseSnough
|
||||||
|
probability: 0.02
|
||||||
|
snoughMessage: disease-screech
|
||||||
|
- !type:DiseaseGenericStatusEffect
|
||||||
|
probability: 0.3
|
||||||
|
key: Stutter
|
||||||
|
component: MonkeyAccent
|
||||||
|
- !type:DiseaseHealthChange
|
||||||
|
probability: 0.53
|
||||||
|
damage:
|
||||||
|
types:
|
||||||
|
Asphyxiation: 1
|
||||||
|
cures:
|
||||||
|
- !type:DiseaseJustWaitCure
|
||||||
|
maxLength: 1600
|
||||||
|
- !type:DiseaseReagentCure
|
||||||
|
reagent: BananaHonk
|
||||||
|
|
||||||
|
- type: disease
|
||||||
|
id: BleedersBite
|
||||||
|
name: Bleeder's Bite
|
||||||
|
effects:
|
||||||
|
- !type:DiseaseAdjustReagent
|
||||||
|
reagent: TranexamicAcid
|
||||||
|
amount: -2.5
|
||||||
|
- !type:DiseaseHealthChange
|
||||||
|
probability: 0.015
|
||||||
|
damage:
|
||||||
|
types:
|
||||||
|
Piercing: 20
|
||||||
|
- !type:DiseasePopUp
|
||||||
|
probability: 0.05
|
||||||
|
message: disease-eaten-inside
|
||||||
|
cures:
|
||||||
|
- !type:DiseaseJustWaitCure
|
||||||
|
maxLength: 900
|
||||||
|
- !type:DiseaseBodyTemperatureCure
|
||||||
|
min: 360
|
||||||
|
- !type:DiseaseReagentCure
|
||||||
|
reagent: DemonsBlood
|
||||||
|
|
||||||
|
- type: disease
|
||||||
|
id: OwOnavirus
|
||||||
|
name: OwOnavirus
|
||||||
|
cureResist: 0.25
|
||||||
|
effects:
|
||||||
|
- !type:DiseaseGenericStatusEffect
|
||||||
|
key: Stutter
|
||||||
|
component: OwOAccent
|
||||||
|
- !type:DiseaseAdjustReagent ## 20 / 0.013 / 60 is around 25 minutes before overdose (0.5u metabolize each tick)
|
||||||
|
probability: 0.513
|
||||||
|
reagent: Ephedrine
|
||||||
|
amount: 1
|
||||||
|
- !type:DiseaseSnough
|
||||||
|
probability: 0.02
|
||||||
|
snoughMessage: disease-meow
|
||||||
|
cures:
|
||||||
|
- !type:DiseaseBodyTemperatureCure
|
||||||
|
min: 420 ## Reachable with a flamer
|
||||||
|
- !type:DiseaseReagentCure
|
||||||
|
reagent: Theobromine
|
||||||
|
amount: 10
|
||||||
18
Resources/Prototypes/Diseases/noninfectious.yml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
- type: disease
|
||||||
|
id: Ultragigacancer
|
||||||
|
name: ultragigacancer
|
||||||
|
infectious: false
|
||||||
|
cureResist: 0.15
|
||||||
|
effects:
|
||||||
|
- !type:DiseaseHealthChange
|
||||||
|
probability: 0.5
|
||||||
|
damage:
|
||||||
|
types:
|
||||||
|
Cellular: 1
|
||||||
|
- !type:DiseasePopUp
|
||||||
|
probability: 0.03
|
||||||
|
cures:
|
||||||
|
- !type:DiseaseReagentCure
|
||||||
|
reagent: Phalanximine
|
||||||
|
min: 15
|
||||||
|
### Once radiation is refactored I want it to have a small chance of giving you regular cancer
|
||||||
@@ -7,3 +7,5 @@
|
|||||||
state: icon
|
state: icon
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
Slots: [gloves]
|
Slots: [gloves]
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.05
|
||||||
|
|||||||
@@ -71,18 +71,33 @@
|
|||||||
sprite: Clothing/Hands/Gloves/ihscombat.rsi
|
sprite: Clothing/Hands/Gloves/ihscombat.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Hands/Gloves/ihscombat.rsi
|
sprite: Clothing/Hands/Gloves/ihscombat.rsi
|
||||||
|
#### Medical
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingHandsBase
|
parent: ClothingHandsBase
|
||||||
id: ClothingHandsGlovesLatex
|
id: ClothingHandsGlovesLatex
|
||||||
name: latex gloves
|
name: latex gloves
|
||||||
description: Thin sterile latex gloves.
|
description: Thin sterile latex gloves. Basic PPE for any doctor.
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Clothing/Hands/Gloves/latex.rsi
|
sprite: Clothing/Hands/Gloves/latex.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Hands/Gloves/latex.rsi
|
sprite: Clothing/Hands/Gloves/latex.rsi
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.1
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: ClothingHandsBase
|
||||||
|
id: ClothingHandsGlovesNitrile
|
||||||
|
name: nitrile gloves
|
||||||
|
description: High-quality nitrile gloves. Expensive medical PPE.
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Clothing/Hands/Gloves/Color/blue.rsi
|
||||||
|
- type: Clothing
|
||||||
|
sprite: Clothing/Hands/Gloves/Color/blue.rsi
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.15
|
||||||
|
####
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingHandsBase
|
parent: ClothingHandsBase
|
||||||
id: ClothingHandsGlovesLeather
|
id: ClothingHandsGlovesLeather
|
||||||
|
|||||||
@@ -48,6 +48,8 @@
|
|||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- HidesHair
|
- HidesHair
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.05
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
abstract: true
|
abstract: true
|
||||||
|
|||||||
@@ -83,6 +83,8 @@
|
|||||||
- type: PressureProtection
|
- type: PressureProtection
|
||||||
highPressureMultiplier: 0.80
|
highPressureMultiplier: 0.80
|
||||||
lowPressureMultiplier: 55
|
lowPressureMultiplier: 55
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.15
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingHeadHardsuitWithLightBase
|
parent: ClothingHeadHardsuitWithLightBase
|
||||||
|
|||||||
@@ -9,9 +9,14 @@
|
|||||||
sprite: Clothing/Head/Hoods/Bio/general.rsi
|
sprite: Clothing/Head/Hoods/Bio/general.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Head/Hoods/Bio/general.rsi
|
sprite: Clothing/Head/Hoods/Bio/general.rsi
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.15
|
||||||
|
- type: Tag
|
||||||
|
tags:
|
||||||
|
- HidesHair
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingHeadBase
|
parent: ClothingHeadHatHoodBioGeneral
|
||||||
id: ClothingHeadHatHoodBioCmo
|
id: ClothingHeadHatHoodBioCmo
|
||||||
name: bio hood
|
name: bio hood
|
||||||
suffix: CMO
|
suffix: CMO
|
||||||
@@ -21,9 +26,11 @@
|
|||||||
sprite: Clothing/Head/Hoods/Bio/cmo.rsi
|
sprite: Clothing/Head/Hoods/Bio/cmo.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Head/Hoods/Bio/cmo.rsi
|
sprite: Clothing/Head/Hoods/Bio/cmo.rsi
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.25
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingHeadBase
|
parent: ClothingHeadHatHoodBioGeneral
|
||||||
id: ClothingHeadHatHoodBioJanitor
|
id: ClothingHeadHatHoodBioJanitor
|
||||||
name: bio hood
|
name: bio hood
|
||||||
suffix: Janitor
|
suffix: Janitor
|
||||||
@@ -34,8 +41,9 @@
|
|||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Head/Hoods/Bio/janitor.rsi
|
sprite: Clothing/Head/Hoods/Bio/janitor.rsi
|
||||||
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingHeadBase
|
parent: ClothingHeadHatHoodBioGeneral
|
||||||
id: ClothingHeadHatHoodBioScientist
|
id: ClothingHeadHatHoodBioScientist
|
||||||
name: bio hood
|
name: bio hood
|
||||||
suffix: Science
|
suffix: Science
|
||||||
@@ -47,7 +55,7 @@
|
|||||||
sprite: Clothing/Head/Hoods/Bio/scientist.rsi
|
sprite: Clothing/Head/Hoods/Bio/scientist.rsi
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingHeadBase
|
parent: ClothingHeadHatHoodBioGeneral
|
||||||
id: ClothingHeadHatHoodBioSecurity
|
id: ClothingHeadHatHoodBioSecurity
|
||||||
name: bio hood
|
name: bio hood
|
||||||
suffix: Security
|
suffix: Security
|
||||||
@@ -59,7 +67,7 @@
|
|||||||
sprite: Clothing/Head/Hoods/Bio/security.rsi
|
sprite: Clothing/Head/Hoods/Bio/security.rsi
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingHeadBase
|
parent: ClothingHeadHatHoodBioGeneral
|
||||||
id: ClothingHeadHatHoodBioVirology
|
id: ClothingHeadHatHoodBioVirology
|
||||||
name: bio hood
|
name: bio hood
|
||||||
suffix: Virology
|
suffix: Virology
|
||||||
@@ -69,6 +77,8 @@
|
|||||||
sprite: Clothing/Head/Hoods/Bio/virology.rsi
|
sprite: Clothing/Head/Hoods/Bio/virology.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Head/Hoods/Bio/virology.rsi
|
sprite: Clothing/Head/Hoods/Bio/virology.rsi
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.25
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingHeadBase
|
parent: ClothingHeadBase
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
sprite: Clothing/Mask/gas.rsi
|
sprite: Clothing/Mask/gas.rsi
|
||||||
- type: BreathMask
|
- type: BreathMask
|
||||||
- type: IngestionBlocker
|
- type: IngestionBlocker
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.05
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingMaskBase
|
parent: ClothingMaskBase
|
||||||
@@ -23,6 +25,8 @@
|
|||||||
sprite: Clothing/Mask/breath.rsi
|
sprite: Clothing/Mask/breath.rsi
|
||||||
- type: BreathMask
|
- type: BreathMask
|
||||||
- type: IngestionBlocker
|
- type: IngestionBlocker
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.05
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingMaskBase
|
parent: ClothingMaskBase
|
||||||
@@ -72,6 +76,8 @@
|
|||||||
sprite: Clothing/Mask/sterile.rsi
|
sprite: Clothing/Mask/sterile.rsi
|
||||||
- type: BreathMask
|
- type: BreathMask
|
||||||
- type: IngestionBlocker
|
- type: IngestionBlocker
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.1
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingMaskBase
|
parent: ClothingMaskBase
|
||||||
|
|||||||
@@ -30,3 +30,4 @@
|
|||||||
Piercing: 0.95
|
Piercing: 0.95
|
||||||
Heat: 0.90
|
Heat: 0.90
|
||||||
Radiation: 0.25
|
Radiation: 0.25
|
||||||
|
- type: DiseaseProtection
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
sprite: Clothing/OuterClothing/Bio/general.rsi
|
sprite: Clothing/OuterClothing/Bio/general.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/OuterClothing/Bio/general.rsi
|
sprite: Clothing/OuterClothing/Bio/general.rsi
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.2
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingOuterBase
|
parent: ClothingOuterBase
|
||||||
@@ -21,6 +23,8 @@
|
|||||||
sprite: Clothing/OuterClothing/Bio/cmo.rsi
|
sprite: Clothing/OuterClothing/Bio/cmo.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/OuterClothing/Bio/cmo.rsi
|
sprite: Clothing/OuterClothing/Bio/cmo.rsi
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.3
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingOuterBase
|
parent: ClothingOuterBase
|
||||||
@@ -33,6 +37,8 @@
|
|||||||
sprite: Clothing/OuterClothing/Bio/janitor.rsi
|
sprite: Clothing/OuterClothing/Bio/janitor.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/OuterClothing/Bio/janitor.rsi
|
sprite: Clothing/OuterClothing/Bio/janitor.rsi
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.2
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingOuterBase
|
parent: ClothingOuterBase
|
||||||
@@ -45,6 +51,8 @@
|
|||||||
sprite: Clothing/OuterClothing/Bio/scientist.rsi
|
sprite: Clothing/OuterClothing/Bio/scientist.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/OuterClothing/Bio/scientist.rsi
|
sprite: Clothing/OuterClothing/Bio/scientist.rsi
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.2
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingOuterBase
|
parent: ClothingOuterBase
|
||||||
@@ -57,6 +65,8 @@
|
|||||||
sprite: Clothing/OuterClothing/Bio/security.rsi
|
sprite: Clothing/OuterClothing/Bio/security.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/OuterClothing/Bio/security.rsi
|
sprite: Clothing/OuterClothing/Bio/security.rsi
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.2
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingOuterBase
|
parent: ClothingOuterBase
|
||||||
@@ -69,3 +79,5 @@
|
|||||||
sprite: Clothing/OuterClothing/Bio/virology.rsi
|
sprite: Clothing/OuterClothing/Bio/virology.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/OuterClothing/Bio/virology.rsi
|
sprite: Clothing/OuterClothing/Bio/virology.rsi
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.3
|
||||||
|
|||||||
@@ -180,6 +180,8 @@
|
|||||||
- type: PressureProtection
|
- type: PressureProtection
|
||||||
highPressureMultiplier: 0.75
|
highPressureMultiplier: 0.75
|
||||||
lowPressureMultiplier: 100
|
lowPressureMultiplier: 100
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.2
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingOuterHardsuitBase
|
parent: ClothingOuterHardsuitBase
|
||||||
|
|||||||
@@ -89,6 +89,8 @@
|
|||||||
sprite: Clothing/Uniforms/Jumpskirt/cmo.rsi
|
sprite: Clothing/Uniforms/Jumpskirt/cmo.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Uniforms/Jumpskirt/cmo.rsi
|
sprite: Clothing/Uniforms/Jumpskirt/cmo.rsi
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.15
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingUniformSkirtBase
|
parent: ClothingUniformSkirtBase
|
||||||
@@ -199,6 +201,8 @@
|
|||||||
sprite: Clothing/Uniforms/Jumpskirt/medical.rsi
|
sprite: Clothing/Uniforms/Jumpskirt/medical.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Uniforms/Jumpskirt/medical.rsi
|
sprite: Clothing/Uniforms/Jumpskirt/medical.rsi
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.1
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingUniformSkirtBase
|
parent: ClothingUniformSkirtBase
|
||||||
@@ -221,6 +225,8 @@
|
|||||||
sprite: Clothing/Uniforms/Jumpskirt/paramedic.rsi
|
sprite: Clothing/Uniforms/Jumpskirt/paramedic.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Uniforms/Jumpskirt/paramedic.rsi
|
sprite: Clothing/Uniforms/Jumpskirt/paramedic.rsi
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.1
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingUniformSkirtBase
|
parent: ClothingUniformSkirtBase
|
||||||
|
|||||||
@@ -161,6 +161,8 @@
|
|||||||
sprite: Clothing/Uniforms/Jumpsuit/cmo.rsi
|
sprite: Clothing/Uniforms/Jumpsuit/cmo.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Uniforms/Jumpsuit/cmo.rsi
|
sprite: Clothing/Uniforms/Jumpsuit/cmo.rsi
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.15
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingUniformBase
|
parent: ClothingUniformBase
|
||||||
@@ -293,6 +295,8 @@
|
|||||||
sprite: Clothing/Uniforms/Jumpsuit/medical.rsi
|
sprite: Clothing/Uniforms/Jumpsuit/medical.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Uniforms/Jumpsuit/medical.rsi
|
sprite: Clothing/Uniforms/Jumpsuit/medical.rsi
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.1
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingUniformBase
|
parent: ClothingUniformBase
|
||||||
@@ -315,6 +319,8 @@
|
|||||||
sprite: Clothing/Uniforms/Jumpsuit/paramedic.rsi
|
sprite: Clothing/Uniforms/Jumpsuit/paramedic.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Uniforms/Jumpsuit/paramedic.rsi
|
sprite: Clothing/Uniforms/Jumpsuit/paramedic.rsi
|
||||||
|
- type: DiseaseProtection
|
||||||
|
protection: 0.1
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingUniformBase
|
parent: ClothingUniformBase
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
- ColdArtifact
|
- ColdArtifact
|
||||||
- RadiateArtifact
|
- RadiateArtifact
|
||||||
- GasArtifact
|
- GasArtifact
|
||||||
|
- DiseaseArtifact
|
||||||
chance: 1
|
chance: 1
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
|
|||||||
@@ -686,6 +686,7 @@
|
|||||||
autoPopulate: false
|
autoPopulate: false
|
||||||
- type: Bloodstream
|
- type: Bloodstream
|
||||||
bloodMaxVolume: 50
|
bloodMaxVolume: 50
|
||||||
|
- type: DiseaseCarrier #The other class lab animal and disease vector
|
||||||
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
@@ -708,6 +709,7 @@
|
|||||||
dead: splat-1
|
dead: splat-1
|
||||||
- type: Bloodstream
|
- type: Bloodstream
|
||||||
bloodMaxVolume: 50
|
bloodMaxVolume: 50
|
||||||
|
- type: DiseaseCarrier #Why doesn't this save if it's only on the parent wtf
|
||||||
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
@@ -730,6 +732,7 @@
|
|||||||
dead: splat-2
|
dead: splat-2
|
||||||
- type: Bloodstream
|
- type: Bloodstream
|
||||||
bloodMaxVolume: 50
|
bloodMaxVolume: 50
|
||||||
|
- type: DiseaseCarrier
|
||||||
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
@@ -775,6 +778,9 @@
|
|||||||
interactFailureString: petting-failure-generic
|
interactFailureString: petting-failure-generic
|
||||||
- type: Bloodstream
|
- type: Bloodstream
|
||||||
bloodMaxVolume: 50
|
bloodMaxVolume: 50
|
||||||
|
- type: Damageable
|
||||||
|
damageContainer: Biological
|
||||||
|
damageModifierSet: Scale
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: frog
|
name: frog
|
||||||
@@ -947,6 +953,9 @@
|
|||||||
interactFailureString: petting-failure-generic
|
interactFailureString: petting-failure-generic
|
||||||
- type: Bloodstream
|
- type: Bloodstream
|
||||||
bloodMaxVolume: 50
|
bloodMaxVolume: 50
|
||||||
|
- type: Damageable
|
||||||
|
damageContainer: Biological
|
||||||
|
damageModifierSet: Scale
|
||||||
|
|
||||||
# Code unique spider prototypes or combine them all into one spider and get a
|
# Code unique spider prototypes or combine them all into one spider and get a
|
||||||
# random sprite state when you spawn it.
|
# random sprite state when you spawn it.
|
||||||
|
|||||||
@@ -71,6 +71,7 @@
|
|||||||
- SlowedDown
|
- SlowedDown
|
||||||
- Stutter
|
- Stutter
|
||||||
- Electrocution
|
- Electrocution
|
||||||
|
- type: DiseaseCarrier
|
||||||
# Other
|
# Other
|
||||||
- type: Inventory
|
- type: Inventory
|
||||||
- type: Clickable
|
- type: Clickable
|
||||||
@@ -294,6 +295,7 @@
|
|||||||
proper: true
|
proper: true
|
||||||
- type: StandingState
|
- type: StandingState
|
||||||
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
save: false
|
save: false
|
||||||
name: Urist McHands
|
name: Urist McHands
|
||||||
|
|||||||
@@ -110,6 +110,25 @@
|
|||||||
template: HumanoidTemplate
|
template: HumanoidTemplate
|
||||||
preset: HumanPreset
|
preset: HumanPreset
|
||||||
- type: LizardAccent
|
- type: LizardAccent
|
||||||
|
- type: DiseaseCarrier
|
||||||
|
diseaseResist: 0.1
|
||||||
|
- type: Damageable
|
||||||
|
damageContainer: Biological
|
||||||
|
damageModifierSet: Scale
|
||||||
|
- type: Temperature
|
||||||
|
heatDamageThreshold: 400
|
||||||
|
coldDamageThreshold: 285
|
||||||
|
currentTemperature: 310.15
|
||||||
|
specificHeat: 46
|
||||||
|
coldDamage:
|
||||||
|
types:
|
||||||
|
Cold : 1.1 #per second, scales with temperature & other constants
|
||||||
|
heatDamage:
|
||||||
|
types:
|
||||||
|
Heat : 0.9 #per second, scales with temperature & other constants
|
||||||
|
- type: MovementSpeedModifier
|
||||||
|
baseWalkSpeed : 2.7
|
||||||
|
baseSprintSpeed : 4.5
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
save: false
|
save: false
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: CircuitImprinterMachineCircuitboard
|
id: CircuitImprinterMachineCircuitboard
|
||||||
parent: BaseMachineCircuitboard
|
parent: BaseMachineCircuitboard
|
||||||
name: Circuit Imprinter (Machine Board)
|
name: circuit imprinter machine board
|
||||||
components:
|
components:
|
||||||
- type: MachineBoard
|
- type: MachineBoard
|
||||||
prototype: CircuitImprinter
|
prototype: CircuitImprinter
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: UniformPrinterMachineCircuitboard
|
id: UniformPrinterMachineCircuitboard
|
||||||
parent: BaseMachineCircuitboard
|
parent: BaseMachineCircuitboard
|
||||||
name: Uniform Printer (Machine Board)
|
name: uniform printer machine board
|
||||||
components:
|
components:
|
||||||
- type: MachineBoard
|
- type: MachineBoard
|
||||||
prototype: UniformPrinter
|
prototype: UniformPrinter
|
||||||
@@ -57,10 +57,41 @@
|
|||||||
Manipulator: 1
|
Manipulator: 1
|
||||||
Laser: 1
|
Laser: 1
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: VaccinatorMachineCircuitboard
|
||||||
|
parent: BaseMachineCircuitboard
|
||||||
|
name: vaccinator machine board
|
||||||
|
components:
|
||||||
|
- type: MachineBoard
|
||||||
|
prototype: Vaccinator
|
||||||
|
requirements:
|
||||||
|
MatterBin: 1
|
||||||
|
Manipulator: 1
|
||||||
|
materialRequirements:
|
||||||
|
Cable: 5
|
||||||
|
tagRequirements:
|
||||||
|
GlassBeaker:
|
||||||
|
Amount: 1
|
||||||
|
DefaultPrototype: Beaker
|
||||||
|
ExamineName: Glass Beaker
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: DiagnoserMachineCircuitboard
|
||||||
|
parent: BaseMachineCircuitboard
|
||||||
|
name: diagnoser machine board
|
||||||
|
components:
|
||||||
|
- type: MachineBoard
|
||||||
|
prototype: DiseaseDiagnoser
|
||||||
|
requirements:
|
||||||
|
Manipulator: 1
|
||||||
|
Laser: 2
|
||||||
|
materialRequirements:
|
||||||
|
Cable: 5
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: ThermomachineFreezerMachineCircuitBoard
|
id: ThermomachineFreezerMachineCircuitBoard
|
||||||
parent: BaseMachineCircuitboard
|
parent: BaseMachineCircuitboard
|
||||||
name: Freezer Thermomachine (Machine Board)
|
name: freezer thermomachine machine board
|
||||||
description: Looks like you could use a screwdriver to change the board type.
|
description: Looks like you could use a screwdriver to change the board type.
|
||||||
components:
|
components:
|
||||||
- type: MachineBoard
|
- type: MachineBoard
|
||||||
@@ -77,7 +108,7 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: ThermomachineHeaterMachineCircuitBoard
|
id: ThermomachineHeaterMachineCircuitBoard
|
||||||
parent: BaseMachineCircuitboard
|
parent: BaseMachineCircuitboard
|
||||||
name: Heater Thermomachine (Machine Board)
|
name: heather thermomachine machine board
|
||||||
description: Looks like you could use a screwdriver to change the board type.
|
description: Looks like you could use a screwdriver to change the board type.
|
||||||
components:
|
components:
|
||||||
- type: MachineBoard
|
- type: MachineBoard
|
||||||
@@ -208,7 +239,7 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
parent: BaseMachineCircuitboard
|
parent: BaseMachineCircuitboard
|
||||||
id: DawInstrumentMachineCircuitboard
|
id: DawInstrumentMachineCircuitboard
|
||||||
name: Digital Audio Workstation (Machine Board)
|
name: digital audio workstation machine board
|
||||||
components:
|
components:
|
||||||
- type: MachineBoard
|
- type: MachineBoard
|
||||||
prototype: DawInstrument
|
prototype: DawInstrument
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
- type: entity
|
||||||
|
parent: BaseItem
|
||||||
|
id: DiseaseSwab
|
||||||
|
name: mouth swab
|
||||||
|
description: Used to take saliva samples to test for diseases.
|
||||||
|
components:
|
||||||
|
- type: Item
|
||||||
|
size: 1
|
||||||
|
- type: Sprite
|
||||||
|
netsync: false
|
||||||
|
sprite: Objects/Specific/Medical/mouth_swab.rsi
|
||||||
|
state: icon
|
||||||
|
- type: Tag
|
||||||
|
tags:
|
||||||
|
- Recyclable
|
||||||
|
- type: DiseaseSwab
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseItem
|
||||||
|
id: Vaccine
|
||||||
|
name: Vaccine
|
||||||
|
description: There's no way you don't already have an opinion on these.
|
||||||
|
components:
|
||||||
|
- type: Item
|
||||||
|
size: 3
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Specific/Medical/medipen.rsi
|
||||||
|
netsync: false
|
||||||
|
state: salpen
|
||||||
|
- type: DiseaseVaccine
|
||||||
@@ -237,3 +237,16 @@
|
|||||||
reagents:
|
reagents:
|
||||||
- ReagentId: TranexamicAcid
|
- ReagentId: TranexamicAcid
|
||||||
Quantity: 15
|
Quantity: 15
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
name: spaceacillin syringe
|
||||||
|
parent: Syringe
|
||||||
|
id: SyringeSpaceacillin
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
injector:
|
||||||
|
maxVol: 15
|
||||||
|
reagents:
|
||||||
|
- ReagentId: Spaceacillin
|
||||||
|
Quantity: 15
|
||||||
|
|||||||
@@ -15,3 +15,23 @@
|
|||||||
- key: enum.HealthAnalyzerUiKey.Key
|
- key: enum.HealthAnalyzerUiKey.Key
|
||||||
type: HealthAnalyzerBoundUserInterface
|
type: HealthAnalyzerBoundUserInterface
|
||||||
- type: HealthAnalyzer
|
- type: HealthAnalyzer
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: HandheldHealthAnalyzer
|
||||||
|
id: HandheldHealthAnalyzerGigacancer
|
||||||
|
suffix: gigacancer
|
||||||
|
components:
|
||||||
|
- type: HealthAnalyzer
|
||||||
|
fake: true
|
||||||
|
disease: Ultragigacancer
|
||||||
|
|
||||||
|
## I know admins will want this
|
||||||
|
- type: entity
|
||||||
|
parent: HandheldHealthAnalyzer
|
||||||
|
id: HandheldHealthAnalyzerOwOnavirus
|
||||||
|
name: OwOnavirus analyzer
|
||||||
|
suffix: admin abuse
|
||||||
|
components:
|
||||||
|
- type: HealthAnalyzer
|
||||||
|
fake: true
|
||||||
|
disease: OwOnavirus
|
||||||
|
|||||||
@@ -167,3 +167,10 @@
|
|||||||
suffix: Gas
|
suffix: Gas
|
||||||
components:
|
components:
|
||||||
- type: GasArtifact
|
- type: GasArtifact
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseXenoArtifact
|
||||||
|
id: DiseaseArtifact
|
||||||
|
suffix: Disease
|
||||||
|
components:
|
||||||
|
- type: DiseaseArtifact
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
- type: entity
|
||||||
|
id: DiseaseDiagnoser
|
||||||
|
parent: BaseMachinePowered
|
||||||
|
name: Disease Diagnoser Delta Extreme
|
||||||
|
description: A machine that analyzes disease samples.
|
||||||
|
placement:
|
||||||
|
mode: SnapgridCenter
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Structures/Machines/diagnoser.rsi
|
||||||
|
layers:
|
||||||
|
- state: icon
|
||||||
|
map: ["enum.DiseaseMachineVisualLayers.IsRunning"]
|
||||||
|
- state: unlit
|
||||||
|
shader: unshaded
|
||||||
|
map: ["enum.DiseaseMachineVisualLayers.IsOn"]
|
||||||
|
netsync: false
|
||||||
|
- type: DiseaseDiagnoser
|
||||||
|
- type: DiseaseMachine
|
||||||
|
machineOutput: Paper
|
||||||
|
- type: Appearance
|
||||||
|
- type: DiseaseMachineVisuals
|
||||||
|
idleState: icon
|
||||||
|
runningState: running
|
||||||
@@ -229,6 +229,9 @@
|
|||||||
- ThermomachineFreezerMachineCircuitBoard
|
- ThermomachineFreezerMachineCircuitBoard
|
||||||
- CloningPodMachineCircuitboard
|
- CloningPodMachineCircuitboard
|
||||||
- MedicalScannerMachineCircuitboard
|
- MedicalScannerMachineCircuitboard
|
||||||
|
- CrewMonitoringComputerCircuitboard
|
||||||
|
- VaccinatorMachineCircuitboard
|
||||||
|
- DiagnoserMachineCircuitboard
|
||||||
- ChemMasterMachineCircuitboard
|
- ChemMasterMachineCircuitboard
|
||||||
- ChemDispenserMachineCircuitboard
|
- ChemDispenserMachineCircuitboard
|
||||||
- HydroponicsTrayMachineCircuitboard
|
- HydroponicsTrayMachineCircuitboard
|
||||||
@@ -237,7 +240,6 @@
|
|||||||
- ProtolatheMachineCircuitboard
|
- ProtolatheMachineCircuitboard
|
||||||
- ReagentGrinderMachineCircuitboard
|
- ReagentGrinderMachineCircuitboard
|
||||||
- UniformPrinterMachineCircuitboard
|
- UniformPrinterMachineCircuitboard
|
||||||
- CrewMonitoringComputerCircuitboard
|
|
||||||
- ShuttleConsoleCircuitboard
|
- ShuttleConsoleCircuitboard
|
||||||
- CircuitImprinterMachineCircuitboard
|
- CircuitImprinterMachineCircuitboard
|
||||||
- DawInstrumentMachineCircuitboard
|
- DawInstrumentMachineCircuitboard
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
- type: entity
|
||||||
|
id: Vaccinator
|
||||||
|
parent: BaseMachinePowered
|
||||||
|
name: Vaccinator
|
||||||
|
description: A machine that creates vaccines.
|
||||||
|
placement:
|
||||||
|
mode: SnapgridCenter
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Structures/Machines/vaccinator.rsi
|
||||||
|
layers:
|
||||||
|
- state: icon
|
||||||
|
map: ["enum.DiseaseMachineVisualLayers.IsRunning"]
|
||||||
|
- state: unlit
|
||||||
|
shader: unshaded
|
||||||
|
map: ["enum.DiseaseMachineVisualLayers.IsOn"]
|
||||||
|
netsync: false
|
||||||
|
- type: DiseaseVaccineCreator
|
||||||
|
- type: DiseaseMachine
|
||||||
|
machineOutput: Vaccine
|
||||||
|
- type: Appearance
|
||||||
|
- type: DiseaseMachineVisuals
|
||||||
|
idleState: icon
|
||||||
|
runningState: running
|
||||||
|
- type: Machine
|
||||||
|
board: VaccinatorMachineCircuitboard
|
||||||
@@ -1,3 +1,11 @@
|
|||||||
|
- type: reagent
|
||||||
|
id: Cryptobiolin
|
||||||
|
name: cryptobiolin
|
||||||
|
group: Medicine
|
||||||
|
desc: Causes confusion and dizziness. This is essential to make Spaceacillin.
|
||||||
|
physicalDesc: fizzy
|
||||||
|
color: "#081a80"
|
||||||
|
|
||||||
- type: reagent
|
- type: reagent
|
||||||
id: Dylovene
|
id: Dylovene
|
||||||
name: dylovene
|
name: dylovene
|
||||||
@@ -308,8 +316,7 @@
|
|||||||
- !type:HealthChange
|
- !type:HealthChange
|
||||||
damage:
|
damage:
|
||||||
types:
|
types:
|
||||||
# close enough to what it says
|
Cellular: -1
|
||||||
Poison: -1
|
|
||||||
Radiation: 1
|
Radiation: 1
|
||||||
|
|
||||||
- type: reagent
|
- type: reagent
|
||||||
@@ -340,6 +347,18 @@
|
|||||||
groups:
|
groups:
|
||||||
Caustic: -5
|
Caustic: -5
|
||||||
|
|
||||||
|
- type: reagent
|
||||||
|
id: Spaceacillin
|
||||||
|
name: spaceacillin
|
||||||
|
group: Medicine
|
||||||
|
desc: A theta-lactam antibiotic. A common and very useful medicine, effective against many diseases likely to be encountered in space. Slows progression of diseases.
|
||||||
|
physicalDesc: opaque
|
||||||
|
color: "#9942f5"
|
||||||
|
metabolisms:
|
||||||
|
Medicine:
|
||||||
|
effects:
|
||||||
|
- !type:ChemCureDisease
|
||||||
|
|
||||||
- type: reagent
|
- type: reagent
|
||||||
id: Stellibinin
|
id: Stellibinin
|
||||||
name: stellibinin
|
name: stellibinin
|
||||||
|
|||||||
@@ -269,3 +269,20 @@
|
|||||||
damage:
|
damage:
|
||||||
types:
|
types:
|
||||||
Poison: 6
|
Poison: 6
|
||||||
|
|
||||||
|
- type: reagent
|
||||||
|
id: VentCrud
|
||||||
|
name: vent crud
|
||||||
|
desc: A jet black substance found in poorly maintained ventilation systems.
|
||||||
|
physicalDesc: sticky
|
||||||
|
color: "#000000"
|
||||||
|
metabolisms:
|
||||||
|
Poison:
|
||||||
|
effects:
|
||||||
|
- !type:HealthChange
|
||||||
|
damage:
|
||||||
|
types:
|
||||||
|
Poison: 2
|
||||||
|
- !type:ChemCauseDisease ##Since this mostly just comes from the event you won't ingest that much
|
||||||
|
causeChance: 0.6
|
||||||
|
disease: VentCough
|
||||||
|
|||||||
@@ -163,6 +163,27 @@
|
|||||||
Steel: 100
|
Steel: 100
|
||||||
Glass: 900
|
Glass: 900
|
||||||
|
|
||||||
|
- type: latheRecipe
|
||||||
|
id: VaccinatorMachineCircuitboard
|
||||||
|
icon: Objects/Misc/module.rsi/id_mod.png
|
||||||
|
result: VaccinatorMachineCircuitboard
|
||||||
|
completetime: 100
|
||||||
|
materials:
|
||||||
|
Steel: 100
|
||||||
|
Glass: 900
|
||||||
|
Gold: 100
|
||||||
|
|
||||||
|
- type: latheRecipe
|
||||||
|
id: DiagnoserMachineCircuitboard
|
||||||
|
icon: Objects/Misc/module.rsi/id_mod.png
|
||||||
|
result: DiagnoserMachineCircuitboard
|
||||||
|
completetime: 100
|
||||||
|
materials:
|
||||||
|
Steel: 100
|
||||||
|
Glass: 900
|
||||||
|
Gold: 100
|
||||||
|
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
id: ReagentGrinderMachineCircuitboard
|
id: ReagentGrinderMachineCircuitboard
|
||||||
icon: Objects/Misc/module.rsi/id_mod.png
|
icon: Objects/Misc/module.rsi/id_mod.png
|
||||||
|
|||||||
@@ -10,6 +10,18 @@
|
|||||||
products:
|
products:
|
||||||
Dylovene: 3
|
Dylovene: 3
|
||||||
|
|
||||||
|
- type: reaction
|
||||||
|
id: Cryptobiolin
|
||||||
|
reactants:
|
||||||
|
Potassium:
|
||||||
|
amount: 1
|
||||||
|
Oxygen:
|
||||||
|
amount: 1
|
||||||
|
Glucose:
|
||||||
|
amount: 1
|
||||||
|
products:
|
||||||
|
Cryptobiolin: 3
|
||||||
|
|
||||||
- type: reaction
|
- type: reaction
|
||||||
id: Arithrazine
|
id: Arithrazine
|
||||||
reactants:
|
reactants:
|
||||||
@@ -288,3 +300,13 @@
|
|||||||
amount: 1
|
amount: 1
|
||||||
products:
|
products:
|
||||||
Siderlac: 2
|
Siderlac: 2
|
||||||
|
|
||||||
|
- type: reaction
|
||||||
|
id: Spaceacillin
|
||||||
|
reactants:
|
||||||
|
Cryptobiolin:
|
||||||
|
amount: 1
|
||||||
|
Inaprovaline:
|
||||||
|
amount: 1
|
||||||
|
products:
|
||||||
|
Spaceacillin: 2
|
||||||
|
|||||||
|
After Width: | Height: | Size: 227 B |
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"size": {
|
||||||
|
"x": 32,
|
||||||
|
"y": 32
|
||||||
|
},
|
||||||
|
"license": "CC-BY",
|
||||||
|
"copyright": "Created by Willhudson#4576 (Discord user id: 935437363180613672) in the SS14 Discord",
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"name": "icon",
|
||||||
|
"directions": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
Resources/Textures/Structures/Machines/diagnoser.rsi/icon.png
Normal file
|
After Width: | Height: | Size: 578 B |
@@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"license": "CC-BY",
|
||||||
|
"copyright": "Created by Willhudson#4576 (Discord user id: 935437363180613672) in the SS14 Discord",
|
||||||
|
"size": {
|
||||||
|
"x": 32,
|
||||||
|
"y": 32
|
||||||
|
},
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"name": "icon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "unlit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "running",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785,
|
||||||
|
0.1785
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
Resources/Textures/Structures/Machines/diagnoser.rsi/running.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
Resources/Textures/Structures/Machines/diagnoser.rsi/unlit.png
Normal file
|
After Width: | Height: | Size: 166 B |
BIN
Resources/Textures/Structures/Machines/vaccinator.rsi/icon.png
Normal file
|
After Width: | Height: | Size: 642 B |
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"license": "CC-BY",
|
||||||
|
"copyright": "Created by Willhudson#4576 (Discord user id: 935437363180613672) in the SS14 Discord",
|
||||||
|
"size": {
|
||||||
|
"x": 32,
|
||||||
|
"y": 32
|
||||||
|
},
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"name": "icon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "unlit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "running",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.5555,
|
||||||
|
0.5555,
|
||||||
|
0.5555,
|
||||||
|
0.5555,
|
||||||
|
0.5555,
|
||||||
|
0.5555,
|
||||||
|
0.5555,
|
||||||
|
0.5555,
|
||||||
|
0.5555
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Resources/Textures/Structures/Machines/vaccinator.rsi/unlit.png
Normal file
|
After Width: | Height: | Size: 174 B |