BloodstreamComponent.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. using Content.Server.Body.Systems;
  2. using Content.Server.Chemistry.EntitySystems;
  3. using Content.Shared.Alert;
  4. using Content.Shared.Chemistry.Components;
  5. using Content.Shared.Chemistry.Reagent;
  6. using Content.Shared.Damage;
  7. using Content.Shared.Damage.Prototypes;
  8. using Content.Shared.FixedPoint;
  9. using Robust.Shared.Audio;
  10. using Robust.Shared.Prototypes;
  11. using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
  12. namespace Content.Server.Body.Components
  13. {
  14. [RegisterComponent, Access(typeof(BloodstreamSystem), typeof(ReactionMixerSystem))]
  15. public sealed partial class BloodstreamComponent : Component
  16. {
  17. public static string DefaultChemicalsSolutionName = "chemicals";
  18. public static string DefaultBloodSolutionName = "bloodstream";
  19. public static string DefaultBloodTemporarySolutionName = "bloodstreamTemporary";
  20. /// <summary>
  21. /// The next time that blood level will be updated and bloodloss damage dealt.
  22. /// </summary>
  23. [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
  24. public TimeSpan NextUpdate;
  25. /// <summary>
  26. /// The interval at which this component updates.
  27. /// </summary>
  28. [DataField]
  29. public TimeSpan UpdateInterval = TimeSpan.FromSeconds(3);
  30. /// <summary>
  31. /// How much is this entity currently bleeding?
  32. /// Higher numbers mean more blood lost every tick.
  33. ///
  34. /// Goes down slowly over time, and items like bandages
  35. /// or clotting reagents can lower bleeding.
  36. /// </summary>
  37. /// <remarks>
  38. /// This generally corresponds to an amount of damage and can't go above 100.
  39. /// </remarks>
  40. [ViewVariables(VVAccess.ReadWrite)]
  41. public float BleedAmount;
  42. /// <summary>
  43. /// How much should bleeding be reduced every update interval?
  44. /// </summary>
  45. [DataField]
  46. public float BleedReductionAmount = 0.33f;
  47. /// <summary>
  48. /// How high can <see cref="BleedAmount"/> go?
  49. /// </summary>
  50. [DataField]
  51. public float MaxBleedAmount = 10.0f;
  52. /// <summary>
  53. /// What percentage of current blood is necessary to avoid dealing blood loss damage?
  54. /// </summary>
  55. [DataField]
  56. public float BloodlossThreshold = 0.75f;
  57. /// <summary>
  58. /// The base bloodloss damage to be incurred if below <see cref="BloodlossThreshold"/>
  59. /// The default values are defined per mob/species in YML.
  60. /// </summary>
  61. [DataField(required: true)]
  62. public DamageSpecifier BloodlossDamage = new();
  63. /// <summary>
  64. /// The base bloodloss damage to be healed if above <see cref="BloodlossThreshold"/>
  65. /// The default values are defined per mob/species in YML.
  66. /// </summary>
  67. [DataField(required: true)]
  68. public DamageSpecifier BloodlossHealDamage = new();
  69. // TODO shouldn't be hardcoded, should just use some organ simulation like bone marrow or smth.
  70. /// <summary>
  71. /// How much reagent of blood should be restored each update interval?
  72. /// </summary>
  73. [DataField]
  74. public FixedPoint2 BloodRefreshAmount = 1.0f;
  75. /// <summary>
  76. /// How much blood needs to be in the temporary solution in order to create a puddle?
  77. /// </summary>
  78. [DataField]
  79. public FixedPoint2 BleedPuddleThreshold = 1.0f;
  80. /// <summary>
  81. /// A modifier set prototype ID corresponding to how damage should be modified
  82. /// before taking it into account for bloodloss.
  83. /// </summary>
  84. /// <remarks>
  85. /// For example, piercing damage is increased while poison damage is nullified entirely.
  86. /// </remarks>
  87. [DataField]
  88. public ProtoId<DamageModifierSetPrototype> DamageBleedModifiers = "BloodlossHuman";
  89. /// <summary>
  90. /// The sound to be played when a weapon instantly deals blood loss damage.
  91. /// </summary>
  92. [DataField]
  93. public SoundSpecifier InstantBloodSound = new SoundCollectionSpecifier("blood");
  94. /// <summary>
  95. /// The sound to be played when some damage actually heals bleeding rather than starting it.
  96. /// </summary>
  97. [DataField]
  98. public SoundSpecifier BloodHealedSound = new SoundPathSpecifier("/Audio/Effects/lightburn.ogg");
  99. /// <summary>
  100. /// The minimum amount damage reduction needed to play the healing sound/popup.
  101. /// This prevents tiny amounts of heat damage from spamming the sound, e.g. spacing.
  102. /// </summary>
  103. [DataField]
  104. public float BloodHealedSoundThreshold = -0.1f;
  105. // TODO probably damage bleed thresholds.
  106. /// <summary>
  107. /// Max volume of internal chemical solution storage
  108. /// </summary>
  109. [DataField]
  110. public FixedPoint2 ChemicalMaxVolume = FixedPoint2.New(250);
  111. /// <summary>
  112. /// Max volume of internal blood storage,
  113. /// and starting level of blood.
  114. /// </summary>
  115. [DataField]
  116. public FixedPoint2 BloodMaxVolume = FixedPoint2.New(300);
  117. /// <summary>
  118. /// Which reagent is considered this entities 'blood'?
  119. /// </summary>
  120. /// <remarks>
  121. /// Slime-people might use slime as their blood or something like that.
  122. /// </remarks>
  123. [DataField]
  124. public ProtoId<ReagentPrototype> BloodReagent = "Blood";
  125. /// <summary>Name/Key that <see cref="BloodSolution"/> is indexed by.</summary>
  126. [DataField]
  127. public string BloodSolutionName = DefaultBloodSolutionName;
  128. /// <summary>Name/Key that <see cref="ChemicalSolution"/> is indexed by.</summary>
  129. [DataField]
  130. public string ChemicalSolutionName = DefaultChemicalsSolutionName;
  131. /// <summary>Name/Key that <see cref="TemporarySolution"/> is indexed by.</summary>
  132. [DataField]
  133. public string BloodTemporarySolutionName = DefaultBloodTemporarySolutionName;
  134. /// <summary>
  135. /// Internal solution for blood storage
  136. /// </summary>
  137. [ViewVariables]
  138. public Entity<SolutionComponent>? BloodSolution;
  139. /// <summary>
  140. /// Internal solution for reagent storage
  141. /// </summary>
  142. [ViewVariables]
  143. public Entity<SolutionComponent>? ChemicalSolution;
  144. /// <summary>
  145. /// Temporary blood solution.
  146. /// When blood is lost, it goes to this solution, and when this
  147. /// solution hits a certain cap, the blood is actually spilled as a puddle.
  148. /// </summary>
  149. [ViewVariables]
  150. public Entity<SolutionComponent>? TemporarySolution;
  151. /// <summary>
  152. /// Variable that stores the amount of status time added by having a low blood level.
  153. /// </summary>
  154. [ViewVariables(VVAccess.ReadWrite)]
  155. public TimeSpan StatusTime;
  156. [DataField]
  157. public ProtoId<AlertPrototype> BleedingAlert = "Bleed";
  158. }
  159. }