using Content.Shared.Alert; using Content.Shared.Body.Systems; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; using Content.Shared.FixedPoint; using Robust.Shared.Audio; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.Body.Components; /// /// Gives an entity a bloodstream. /// [RegisterComponent, NetworkedComponent,] [AutoGenerateComponentState(fieldDeltas: true), AutoGenerateComponentPause] [Access(typeof(SharedBloodstreamSystem))] public sealed partial class BloodstreamComponent : Component { public const string DefaultChemicalsSolutionName = "chemicals"; public const string DefaultBloodSolutionName = "bloodstream"; public const string DefaultBloodTemporarySolutionName = "bloodstreamTemporary"; /// /// The next time that blood level will be updated and bloodloss damage dealt. /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] [AutoNetworkedField, AutoPausedField] public TimeSpan NextUpdate; /// /// The interval at which this component updates. /// [DataField, AutoNetworkedField] public TimeSpan UpdateInterval = TimeSpan.FromSeconds(3); /// /// Multiplier applied to for adjusting based on metabolic rate multiplier. /// [DataField, AutoNetworkedField] public float UpdateIntervalMultiplier = 1f; /// /// Adjusted update interval based off of the multiplier value. /// [ViewVariables] public TimeSpan AdjustedUpdateInterval => UpdateInterval * UpdateIntervalMultiplier; /// /// How much is this entity currently bleeding? /// Higher numbers mean more blood lost every tick. /// /// Goes down slowly over time, and items like bandages /// or clotting reagents can lower bleeding. /// /// /// This generally corresponds to an amount of damage and can't go above 100. /// [DataField, AutoNetworkedField] public float BleedAmount; /// /// How much should bleeding be reduced every update interval? /// [DataField, AutoNetworkedField] public float BleedReductionAmount = 0.33f; /// /// How high can go? /// [DataField, AutoNetworkedField] public float MaxBleedAmount = 10.0f; /// /// What percentage of current blood is necessary to avoid dealing blood loss damage? /// [DataField, AutoNetworkedField] public float BloodlossThreshold = 0.9f; /// /// The base bloodloss damage to be incurred if below /// The default values are defined per mob/species in YML. /// [DataField(required: true), AutoNetworkedField] public DamageSpecifier? BloodlossDamage = new(); // Offbrand: we don't need this /// /// The base bloodloss damage to be healed if above /// The default values are defined per mob/species in YML. /// [DataField(required: true), AutoNetworkedField] public DamageSpecifier? BloodlossHealDamage = new(); // Offbrand: we don't need this // TODO shouldn't be hardcoded, should just use some organ simulation like bone marrow or smth. /// /// How much reagent of blood should be restored each update interval? /// [DataField, AutoNetworkedField] public FixedPoint2 BloodRefreshAmount = 1.0f; /// /// How much blood needs to be in the temporary solution in order to create a puddle? /// [DataField, AutoNetworkedField] public FixedPoint2 BleedPuddleThreshold = 1.0f; /// /// A modifier set prototype ID corresponding to how damage should be modified /// before taking it into account for bloodloss. /// /// /// For example, piercing damage is increased while poison damage is nullified entirely. /// [DataField, AutoNetworkedField] public ProtoId? DamageBleedModifiers = "BloodlossHuman"; // Offbrand: we don't want this /// /// The sound to be played when a weapon instantly deals blood loss damage. /// [DataField, AutoNetworkedField] public SoundSpecifier InstantBloodSound = new SoundCollectionSpecifier("blood"); /// /// The sound to be played when some damage actually heals bleeding rather than starting it. /// [DataField] public SoundSpecifier BloodHealedSound = new SoundPathSpecifier("/Audio/Effects/lightburn.ogg"); /// /// The minimum amount damage reduction needed to play the healing sound/popup. /// This prevents tiny amounts of heat damage from spamming the sound, e.g. spacing. /// [DataField] public float BloodHealedSoundThreshold = -0.1f; // TODO probably damage bleed thresholds. /// /// Max volume of internal chemical solution storage /// [DataField] public FixedPoint2 ChemicalMaxVolume = FixedPoint2.New(250); /// /// Max volume of internal blood storage, /// and starting level of blood. /// [DataField] public FixedPoint2 BloodMaxVolume = FixedPoint2.New(300); /// /// Which reagent is considered this entities 'blood'? /// /// /// Slime-people might use slime as their blood or something like that. /// [DataField, AutoNetworkedField] public ProtoId BloodReagent = "Blood"; /// /// Name/Key that is indexed by. /// [DataField] public string BloodSolutionName = DefaultBloodSolutionName; /// /// Name/Key that is indexed by. /// [DataField] public string ChemicalSolutionName = DefaultChemicalsSolutionName; /// /// Name/Key that is indexed by. /// [DataField] public string BloodTemporarySolutionName = DefaultBloodTemporarySolutionName; /// /// Internal solution for blood storage /// [ViewVariables] public Entity? BloodSolution; /// /// Internal solution for reagent storage /// [ViewVariables] public Entity? ChemicalSolution; /// /// Temporary blood solution. /// When blood is lost, it goes to this solution, and when this /// solution hits a certain cap, the blood is actually spilled as a puddle. /// [ViewVariables] public Entity? TemporarySolution; /// /// Alert to show when bleeding. /// [DataField] public ProtoId BleedingAlert = "Bleed"; }