Basic bleeding mechanics (#6710)

This commit is contained in:
mirrorcult
2022-02-17 15:00:41 -07:00
committed by GitHub
parent 56b2041b12
commit a57d78a3f2
29 changed files with 510 additions and 48 deletions

View File

@@ -1,28 +1,136 @@
using Content.Server.Atmos;
using Content.Server.Body.Systems;
using Content.Shared.Atmos;
using Content.Shared.Chemistry.Components;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.FixedPoint;
using Robust.Shared.Analyzers;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
using Content.Shared.Sound;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Server.Body.Components
{
[RegisterComponent, Friend(typeof(BloodstreamSystem))]
public sealed class BloodstreamComponent : Component
{
public static string DefaultChemicalsSolutionName = "chemicals";
public static string DefaultBloodSolutionName = "bloodstream";
public static string DefaultBloodTemporarySolutionName = "bloodstreamTemporary";
public float AccumulatedFrametime = 0.0f;
/// <summary>
/// Max volume of internal solution storage
/// 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.
/// </summary>
[DataField("maxVolume")]
public FixedPoint2 InitialMaxVolume = FixedPoint2.New(250);
/// <remarks>
/// This generally corresponds to an amount of damage and can't go above 100.
/// </remarks>
[ViewVariables(VVAccess.ReadWrite)]
public float BleedAmount;
/// <summary>
/// How much should bleeding should be reduced every update interval?
/// </summary>
[DataField("bleedReductionAmount")]
public float BleedReductionAmount = 1.0f;
/// <summary>
/// What percentage of current blood is necessary to avoid dealing blood loss damage?
/// </summary>
[DataField("bloodlossThreshold")]
public float BloodlossThreshold = 0.9f;
/// <summary>
/// The base bloodloss damage to be incurred if below <see cref="BloodlossThreshold"/>
/// </summary>
[DataField("bloodlossDamage", required: true)]
public DamageSpecifier BloodlossDamage = default!;
/// <summary>
/// The base bloodloss damage to be healed if above <see cref="BloodlossThreshold"/>
/// </summary>
[DataField("bloodlossHealDamage", required: true)]
public DamageSpecifier BloodlossHealDamage = default!;
/// <summary>
/// How frequently should this bloodstream update, in seconds?
/// </summary>
[DataField("updateInterval")]
public float UpdateInterval = 5.0f;
// TODO shouldn't be hardcoded, should just use some organ simulation like bone marrow or smth.
/// <summary>
/// How much reagent of blood should be restored each update interval?
/// </summary>
[DataField("bloodRefreshAmount")]
public float BloodRefreshAmount = 0.2f;
/// <summary>
/// How much blood needs to be in the temporary solution in order to create a puddle?
/// </summary>
[DataField("bleedPuddleThreshold")]
public FixedPoint2 BleedPuddleThreshold = 10.0f;
/// <summary>
/// A modifier set prototype ID corresponding to how damage should be modified
/// before taking it into account for bloodloss.
/// </summary>
/// <remarks>
/// For example, piercing damage is increased while poison damage is nullified entirely.
/// </remarks>
[DataField("damageBleedModifiers", customTypeSerializer:typeof(PrototypeIdSerializer<DamageModifierSetPrototype>))]
public string DamageBleedModifiers = "BloodlossHuman";
/// <summary>
/// The sound to be played when a weapon instantly deals blood loss damage.
/// </summary>
[DataField("instantBloodSound")]
public SoundSpecifier InstantBloodSound = new SoundCollectionSpecifier("blood");
// TODO probably damage bleed thresholds.
/// <summary>
/// Max volume of internal chemical solution storage
/// </summary>
[DataField("chemicalMaxVolume")]
public FixedPoint2 ChemicalMaxVolume = FixedPoint2.New(250);
/// <summary>
/// Max volume of internal blood storage,
/// and starting level of blood.
/// </summary>
[DataField("bloodMaxVolume")]
public FixedPoint2 BloodMaxVolume = FixedPoint2.New(300);
/// <summary>
/// Which reagent is considered this entities 'blood'?
/// </summary>
/// <remarks>
/// Slime-people might use slime as their blood or something like that.
/// </remarks>
[DataField("bloodReagent")]
public string BloodReagent = "Blood";
/// <summary>
/// Internal solution for reagent storage
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public Solution Solution = default!;
public Solution ChemicalSolution = default!;
/// <summary>
/// Internal solution for blood storage
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public Solution BloodSolution = default!;
/// <summary>
/// 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.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public Solution BloodTemporarySolution = default!;
}
}

View File

@@ -30,7 +30,7 @@ namespace Content.Server.Body.Components
/// From which solution will this metabolizer attempt to metabolize chemicals
/// </summary>
[DataField("solution")]
public string SolutionName { get; set; } = BloodstreamSystem.DefaultSolutionName;
public string SolutionName { get; set; } = BloodstreamComponent.DefaultChemicalsSolutionName;
/// <summary>
/// Does this component use a solution on it's parent entity (the body) or itself

View File

@@ -24,7 +24,7 @@ namespace Content.Server.Body.Components
/// What solution should this stomach push reagents into, on the body?
/// </summary>
[DataField("bodySolutionName")]
public string BodySolutionName = BloodstreamSystem.DefaultSolutionName;
public string BodySolutionName = BloodstreamComponent.DefaultChemicalsSolutionName;
/// <summary>
/// Initial internal solution storage volume

View File

@@ -1,47 +1,193 @@
using System;
using Content.Server.Atmos;
using Content.Server.Atmos.EntitySystems;
using System.Linq;
using Content.Server.Body.Components;
using Content.Server.Chemistry.EntitySystems;
using Content.Server.Fluids.EntitySystems;
using Content.Shared.Chemistry.Components;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Examine;
using Content.Shared.FixedPoint;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Content.Shared.MobState.Components;
using Robust.Shared.Audio;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server.Body.Systems;
public sealed class BloodstreamSystem : EntitySystem
{
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
[Dependency] private readonly AtmosphereSystem _atmosSystem = default!;
[Dependency] private readonly RespiratorSystem _respiratorSystem = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly SpillableSystem _spillableSystem = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!;
public static string DefaultSolutionName = "bloodstream";
// TODO here
// Update over time. Modify bloodloss damage in accordance with (amount of blood / max blood level), and reduce bleeding over time
// Sub to damage changed event and modify bloodloss if incurring large hits of slashing/piercing
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<BloodstreamComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<BloodstreamComponent, DamageChangedEvent>(OnDamageChanged);
SubscribeLocalEvent<BloodstreamComponent, ExaminedEvent>(OnExamined);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
foreach (var bloodstream in EntityManager.EntityQuery<BloodstreamComponent>())
{
bloodstream.AccumulatedFrametime += frameTime;
if (bloodstream.AccumulatedFrametime < bloodstream.UpdateInterval)
continue;
bloodstream.AccumulatedFrametime -= bloodstream.UpdateInterval;
var uid = bloodstream.Owner;
if (TryComp<MobStateComponent>(uid, out var state) && state.IsDead())
continue;
// First, let's refresh their blood if possible.
if (bloodstream.BloodSolution.CurrentVolume < bloodstream.BloodSolution.MaxVolume)
TryModifyBloodLevel(uid, bloodstream.BloodRefreshAmount, bloodstream);
// Next, let's remove some blood from them according to their bleed level.
// as well as stop their bleeding to a certain extent.
if (bloodstream.BleedAmount > 0)
{
TryModifyBloodLevel(uid, (-bloodstream.BleedAmount) / 10, bloodstream);
TryModifyBleedAmount(uid, -bloodstream.BleedReductionAmount, bloodstream);
}
// Next, we'll deal some bloodloss damage if their blood level is below a threshold.
var bloodPercentage = GetBloodLevelPercentage(uid, bloodstream);
if (bloodPercentage < bloodstream.BloodlossThreshold)
{
// TODO use a better method for determining this.
var amt = bloodstream.BloodlossDamage / bloodPercentage;
_damageableSystem.TryChangeDamage(uid, amt, true, false);
}
else
{
// If they're healthy, we'll try and heal some bloodloss instead.
_damageableSystem.TryChangeDamage(uid, bloodstream.BloodlossHealDamage * bloodPercentage, true, false);
}
}
}
private void OnComponentInit(EntityUid uid, BloodstreamComponent component, ComponentInit args)
{
component.Solution = _solutionContainerSystem.EnsureSolution(uid, DefaultSolutionName);
if (component.Solution != null)
component.ChemicalSolution = _solutionContainerSystem.EnsureSolution(uid, BloodstreamComponent.DefaultChemicalsSolutionName);
component.BloodSolution = _solutionContainerSystem.EnsureSolution(uid, BloodstreamComponent.DefaultBloodSolutionName);
component.BloodTemporarySolution = _solutionContainerSystem.EnsureSolution(uid, BloodstreamComponent.DefaultBloodTemporarySolutionName);
component.ChemicalSolution.MaxVolume = component.ChemicalMaxVolume;
component.BloodSolution.MaxVolume = component.BloodMaxVolume;
component.BloodTemporarySolution.MaxVolume = component.BleedPuddleThreshold * 2; // give some leeway
// Fill blood solution with BLOOD
_solutionContainerSystem.TryAddReagent(uid, component.BloodSolution, component.BloodReagent,
component.BloodMaxVolume, out _);
}
private void OnDamageChanged(EntityUid uid, BloodstreamComponent component, DamageChangedEvent args)
{
if (args.DamageDelta is null)
return;
// TODO probably cache this or something. humans get hurt a lot
if (!_prototypeManager.TryIndex<DamageModifierSetPrototype>(component.DamageBleedModifiers, out var modifiers))
return;
var bloodloss = DamageSpecifier.ApplyModifierSet(args.DamageDelta, modifiers);
if (bloodloss.Empty)
return;
var total = bloodloss.Total;
var totalFloat = total.Float();
TryModifyBleedAmount(uid, totalFloat, component);
var prob = Math.Clamp(totalFloat / 50, 0, 1);
if (_robustRandom.Prob(prob))
{
component.Solution.MaxVolume = component.InitialMaxVolume;
// This is gonna hurt.
TryModifyBloodLevel(uid, (-total) / 5, component);
SoundSystem.Play(Filter.Pvs(uid), component.InstantBloodSound.GetSound(), uid, AudioParams.Default);
}
}
private void OnExamined(EntityUid uid, BloodstreamComponent component, ExaminedEvent args)
{
if (GetBloodLevelPercentage(uid, component) < component.BloodlossThreshold)
{
args.PushMarkup(Loc.GetString("bloodstream-component-looks-pale", ("target", uid)));
}
}
/// <summary>
/// Attempt to transfer provided solution to internal solution.
/// </summary>
public bool TryAddToBloodstream(EntityUid uid, Solution solution, BloodstreamComponent? component=null)
public bool TryAddToChemicals(EntityUid uid, Solution solution, BloodstreamComponent? component=null)
{
if (!Resolve(uid, ref component, false))
return false;
return _solutionContainerSystem.TryAddSolution(uid, component.Solution, solution);
return _solutionContainerSystem.TryAddSolution(uid, component.ChemicalSolution, solution);
}
public float GetBloodLevelPercentage(EntityUid uid, BloodstreamComponent? component = null)
{
if (!Resolve(uid, ref component))
return 0.0f;
return (component.BloodSolution.CurrentVolume / component.BloodSolution.MaxVolume).Float();
}
/// <summary>
/// Attempts to modify the blood level of this entity directly.
/// </summary>
public bool TryModifyBloodLevel(EntityUid uid, FixedPoint2 amount, BloodstreamComponent? component = null)
{
if (!Resolve(uid, ref component, false))
return false;
if (amount >= 0)
return _solutionContainerSystem.TryAddReagent(uid, component.BloodSolution, component.BloodReagent, amount, out _);
// Removal is more involved,
// since we also wanna handle moving it to the temporary solution
// and then spilling it if necessary.
var newSol = component.BloodSolution.SplitSolution(-amount);
component.BloodTemporarySolution.AddSolution(newSol);
if (component.BloodTemporarySolution.MaxVolume > component.BleedPuddleThreshold)
{
_spillableSystem.SpillAt(uid, component.BloodTemporarySolution, "PuddleBlood", false);
component.BloodTemporarySolution.RemoveAllSolution();
}
return true;
}
/// <summary>
/// Tries to make an entity bleed more or less
/// </summary>
public bool TryModifyBleedAmount(EntityUid uid, float amount, BloodstreamComponent? component = null)
{
if (!Resolve(uid, ref component, false))
return false;
component.BleedAmount += amount;
component.BleedAmount = Math.Clamp(component.BleedAmount, 0, 40);
return true;
}
}

View File

@@ -61,10 +61,10 @@ namespace Content.Server.Chemistry.Components
var cloneSolution = solution.Clone();
var transferAmount = FixedPoint2.Min(cloneSolution.TotalVolume * solutionFraction * (1 - protection),
bloodstream.Solution.AvailableVolume);
bloodstream.ChemicalSolution.AvailableVolume);
var transferSolution = cloneSolution.SplitSolution(transferAmount);
bloodstreamSys.TryAddToBloodstream(entity, transferSolution, bloodstream);
bloodstreamSys.TryAddToChemicals(entity, transferSolution, bloodstream);
}
protected override void OnKill()

View File

@@ -41,7 +41,7 @@ namespace Content.Server.Chemistry.Components
var chemistry = EntitySystem.Get<ReactiveSystem>();
var cloneSolution = solution.Clone();
var transferAmount = FixedPoint2.Min(cloneSolution.TotalVolume * solutionFraction, bloodstream.Solution.AvailableVolume);
var transferAmount = FixedPoint2.Min(cloneSolution.TotalVolume * solutionFraction, bloodstream.ChemicalSolution.AvailableVolume);
var transferSolution = cloneSolution.SplitSolution(transferAmount);
foreach (var reagentQuantity in transferSolution.Contents.ToArray())
@@ -51,7 +51,7 @@ namespace Content.Server.Chemistry.Components
}
var bloodstreamSys = EntitySystem.Get<BloodstreamSystem>();
bloodstreamSys.TryAddToBloodstream(entity, transferSolution, bloodstream);
bloodstreamSys.TryAddToChemicals(entity, transferSolution, bloodstream);
}

View File

@@ -247,7 +247,7 @@ public sealed partial class ChemistrySystem
private void TryInjectIntoBloodstream(InjectorComponent component, BloodstreamComponent targetBloodstream, EntityUid user)
{
// Get transfer amount. May be smaller than _transferAmount if not enough room
var realTransferAmount = FixedPoint2.Min(component.TransferAmount, targetBloodstream.Solution.AvailableVolume);
var realTransferAmount = FixedPoint2.Min(component.TransferAmount, targetBloodstream.ChemicalSolution.AvailableVolume);
if (realTransferAmount <= 0)
{
@@ -257,9 +257,9 @@ public sealed partial class ChemistrySystem
}
// Move units from attackSolution to targetSolution
var removedSolution = _solutions.SplitSolution(user, targetBloodstream.Solution, realTransferAmount);
var removedSolution = _solutions.SplitSolution(user, targetBloodstream.ChemicalSolution, realTransferAmount);
_blood.TryAddToBloodstream((targetBloodstream).Owner, removedSolution, targetBloodstream);
_blood.TryAddToChemicals((targetBloodstream).Owner, removedSolution, targetBloodstream);
removedSolution.DoEntityReaction(targetBloodstream.Owner, ReactionMethod.Injection);

View File

@@ -38,7 +38,7 @@ namespace Content.Server.Chemistry.EntitySystems
var solToInject = solRemoved.SplitSolution(solRemovedVol * component.TransferEfficiency);
_bloodstreamSystem.TryAddToBloodstream((args.OtherFixture.Body).Owner, solToInject, bloodstream);
_bloodstreamSystem.TryAddToChemicals((args.OtherFixture.Body).Owner, solToInject, bloodstream);
}
}
}

View File

@@ -0,0 +1,25 @@
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
namespace Content.Server.Chemistry.ReagentEffects;
public sealed class ModifyBleedAmount : ReagentEffect
{
[DataField("scaled")]
public bool Scaled = false;
[DataField("amount")]
public float Amount = -1.0f;
public override void Effect(ReagentEffectArgs args)
{
if (args.EntityManager.TryGetComponent<BloodstreamComponent>(args.SolutionEntity, out var blood))
{
var sys = EntitySystem.Get<BloodstreamSystem>();
var amt = Scaled ? Amount * args.Quantity.Float() : Amount;
sys.TryModifyBleedAmount(args.SolutionEntity, amt, blood);
}
}
}

View File

@@ -0,0 +1,25 @@
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
namespace Content.Server.Chemistry.ReagentEffects;
public sealed class ModifyBloodLevel : ReagentEffect
{
[DataField("scaled")]
public bool Scaled = false;
[DataField("amount")]
public FixedPoint2 Amount = 1.0f;
public override void Effect(ReagentEffectArgs args)
{
if (args.EntityManager.TryGetComponent<BloodstreamComponent>(args.SolutionEntity, out var blood))
{
var sys = EntitySystem.Get<BloodstreamSystem>();
var amt = Scaled ? Amount * args.Quantity : Amount;
sys.TryModifyBloodLevel(args.SolutionEntity, amt, blood);
}
}
}

View File

@@ -18,6 +18,14 @@ namespace Content.Server.Medical.Components
[ViewVariables(VVAccess.ReadWrite)]
public DamageSpecifier Damage = default!;
/// <remarks>
/// This should generally be negative,
/// since you're, like, trying to heal damage.
/// </remarks>
[DataField("bloodlossModifier")]
[ViewVariables(VVAccess.ReadWrite)]
public float BloodlossModifier = 0.0f;
/// <remarks>
/// The supported damage types are specified using a <see cref="DamageContainerPrototype"/>s. For a
/// HealingComponent this filters what damage container type this component should work on. If null,

View File

@@ -1,5 +1,6 @@
using System.Threading;
using Content.Server.Administration.Logs;
using Content.Server.Body.Systems;
using Content.Server.DoAfter;
using Content.Server.Medical.Components;
using Content.Server.Stack;
@@ -17,6 +18,7 @@ public sealed class HealingSystem : EntitySystem
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
[Dependency] private readonly AdminLogSystem _logs = default!;
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!;
[Dependency] private readonly DoAfterSystem _doAfter = default!;
[Dependency] private readonly StackSystem _stacks = default!;
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
@@ -37,6 +39,12 @@ public sealed class HealingSystem : EntitySystem
if (component.DamageContainerID is not null &&
!component.DamageContainerID.Equals(component.DamageContainerID)) return;
if (args.Component.BloodlossModifier != 0)
{
// Heal some bloodloss damage.
_bloodstreamSystem.TryModifyBleedAmount(uid, args.Component.BloodlossModifier);
}
var healed = _damageable.TryChangeDamage(uid, args.Component.Damage, true);
// Reverify that we can heal the damage.

View File

@@ -117,7 +117,7 @@ namespace Content.Server.Nutrition.EntitySystems
continue;
_reactiveSystem.ReactionEntity(containerManager.Owner, ReactionMethod.Ingestion, inhaledSolution);
_bloodstreamSystem.TryAddToBloodstream(containerManager.Owner, inhaledSolution, bloodstream);
_bloodstreamSystem.TryAddToChemicals(containerManager.Owner, inhaledSolution, bloodstream);
}
_timer -= UpdateTimer;

View File

@@ -295,7 +295,7 @@ namespace Content.Server.Weapon.Melee
foreach (var bloodstream in hitBloodstreams)
{
var individualInjection = solutionToInject.SplitSolution(volPerBloodstream);
_bloodstreamSystem.TryAddToBloodstream((bloodstream).Owner, individualInjection, bloodstream);
_bloodstreamSystem.TryAddToChemicals((bloodstream).Owner, individualInjection, bloodstream);
}
}

View File

@@ -0,0 +1,2 @@
blood1.ogg under CC-0 from https://freesound.org/people/kyles/sounds/453769/
blood2.ogg under CC-BY 3.0 from https://freesound.org/people/EminYILDIRIM/sounds/554284/

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
bloodstream-component-looks-pale = [color=bisque]{CAPITALIZE(SUBJECT($target))} looks pale.[/color]

View File

@@ -72,3 +72,20 @@
Cold: 1.5
Poison: 0.8
# Represents which damage types should be modified
# in relation to how they cause bloodloss damage.
- type: damageModifierSet
id: BloodlossHuman
coefficients:
Blunt: 0.8
Slash: 2.5
Piercing: 2.0
Shock: 0.0
Cold: 0.0
Heat: 0.0
Poison: 0.0
Radiation: 0.0
Asphyxiation: 0.0
Bloodloss: 0.0 # no double dipping
Cellular: 0.0

View File

@@ -88,6 +88,25 @@
visuals:
- type: PuddleVisualizer
- type: entity
id: PuddleBlood
name: blood
description: This can't be a good sign.
parent: PuddleBase
components:
- type: Sprite
sprite: Fluids/splatter.rsi # Placeholder
state: splatter-0
netsync: false
- type: Puddle
slipThreshold: 20
- type: Evaporation
evaporateTime: 20 # 4 times slower than normal
- type: Appearance
visuals:
- type: PuddleVisualizer
recolor: true
- type: entity
name: vomit
id: PuddleVomit

View File

@@ -53,7 +53,14 @@
- Opaque
- type: SolutionContainerManager
- type: Bloodstream
max_volume: 100
bloodlossDamage:
types:
Bloodloss:
1
bloodlossHealDamage:
types:
Bloodloss:
-0.25
- type: Damageable
damageContainer: Biological
- type: AtmosExposed

View File

@@ -44,16 +44,19 @@
types:
Blunt: 2
# Organs
- type: SolutionContainerManager
solutions:
bloodstream:
maxVol: 250
- type: InjectableSolution
solution: bloodstream
solution: chemicals
- type: DrawableSolution
solution: bloodstream
- type: Bloodstream
max_volume: 100
bloodlossDamage:
types:
Bloodloss:
1
bloodlossHealDamage:
types:
Bloodloss:
-0.25
- type: StatusEffects
allowed:
- Stun

View File

@@ -99,6 +99,16 @@
- type: Damageable
damageContainer: Biological
damageModifierSet: Slime
- type: Bloodstream
bloodReagent: Slime # TODO Color slime blood based on their slime color or smth
bloodlossDamage:
types:
Bloodloss:
1
bloodlossHealDamage:
types:
Bloodloss:
-0.25
- type: Barotrauma
damage:
types:

View File

@@ -39,6 +39,7 @@
damage:
groups:
Brute: -15 # 5 for each type in the group
bloodlossModifier: -3 # a little bit of bloodloss healing.
- type: Stack
stackType: Brutepack
@@ -57,8 +58,9 @@
damageContainer: Biological
damage:
types:
Slash: -5
Piercing: -5
Slash: -2.5
Piercing: -2.5
bloodlossModifier: -10
- type: Stack
stackType: Gauze

View File

@@ -0,0 +1,30 @@
- type: reagent
id: Blood
name: blood
group: Biological
desc: I hope this is ketchup.
color: "#9e1010"
physicalDesc: ferrous
metabolisms:
Drink:
# Quenching!
effects:
- !type:SatiateThirst
factor: 1.5
plantMetabolism:
- !type:PlantAdjustWater
amount: 0.5
- type: reagent
id: Slime
name: slime
group: Biological
desc: You thought this was gradient blood at first, but you were mistaken.
color: "#2cf274"
physicalDesc: viscous
metabolisms:
Food:
# Delicious!
effects:
- !type:SatiateHunger
factor: 1.5

View File

@@ -105,6 +105,12 @@
color: "#434b4d"
boilingPoint: 2862.0
meltingPoint: 1538.0
metabolisms:
Medicine:
effects:
- !type:ModifyBloodLevel
scaled: true # scales 2x with the amount of iron you consume
amount: 2
- type: reagent
id: Lithium

View File

@@ -158,7 +158,7 @@
id: Dexalin
name: dexalin
group: Medicine
desc: Used for treating oxygen deprivation. In most cases where it is likely to be needed, the strength of Dexalin Plus will probably be more useful (Results in 1 unit instead of 2).
desc: Used for treating oxygen deprivation. In most cases where it is likely to be needed, the strength of Dexalin Plus will probably be more useful.
physicalDesc: opaque
color: "#0041a8"
metabolisms:
@@ -168,12 +168,13 @@
damage:
types:
Asphyxiation: -1
Bloodloss: -0.5
- type: reagent
id: DexalinPlus
name: dexalin plus
group: Medicine
desc: Used in treatment of extreme cases of oxygen deprivation. Even a single unit immediately counters all oxygen loss, which is hugely useful in many circumstances. Any dose beyond this will continue to counter oxygen loss until it is metabolized, essentially removing the need to breathe.
desc: Used in treatment of extreme cases of oxygen deprivation. Effective at healing blood loss damage.
physicalDesc: cloudy
color: "#4da0bd"
metabolisms:
@@ -183,6 +184,7 @@
damage:
types:
Asphyxiation: -3
Bloodloss: -2
- type: reagent
id: Ethylredoxrazine
@@ -299,7 +301,7 @@
id: Inaprovaline
name: inaprovaline
group: Medicine
desc: Inaprovaline is a synaptic stimulant and cardiostimulant. Commonly used to stabilize patients- it stops oxygen loss when the patient is in critical health. It'll also slow down bleeding (internal or external) by half while in the body. Acts as a decent painkiller.
desc: Inaprovaline is a synaptic stimulant and cardiostimulant. Commonly used to stabilize patients- it stops oxygen loss when the patient is in critical health. It'll also slow down bleeding by a good amount. Acts as a decent painkiller.
physicalDesc: opaque
color: "#731024"
metabolisms:
@@ -313,6 +315,9 @@
damage:
types:
Asphyxiation: -5
- !type:ModifyBleedAmount
scaled: true
amount: -0.25
- type: reagent
id: Kelotane
@@ -443,6 +448,28 @@
physicalDesc: strong-smelling
color: "#2f6ed4"
- type: reagent
id: TranexamicAcid
name: tranexamic acid
group: Medicine
desc: A blood clotting medicine for preventing heavy bleeding. Very dangerous in large quantities.
physicalDesc: viscous
color: "#ba7d7d"
metabolisms:
Medicine:
effects:
# Medium-large quantities can hurt you instead,
# but still technically stop your bleeding.
- !type:ModifyBleedAmount
scaled: true
- !type:HealthChange
conditions:
- !type:ReagentThreshold
min: 15
damage:
types:
Bloodloss: 3
- type: reagent
id: Tricordrazine
name: tricordrazine

View File

@@ -212,6 +212,18 @@
products:
Inaprovaline: 3
- type: reaction
id: TranexamicAcid
reactants:
Inaprovaline:
amount: 1
SulfuricAcid:
amount: 1
Glucose:
amount: 1
products:
TranexamicAcid: 3
- type: reaction
id: Kelotane
reactants:

View File

@@ -4,3 +4,9 @@
- /Audio/Effects/gib1.ogg
- /Audio/Effects/gib2.ogg
- /Audio/Effects/gib3.ogg
- type: soundCollection
id: blood
files:
- /Audio/Effects/Fluids/blood1.ogg
- /Audio/Effects/Fluids/blood2.ogg