Ejemplo n.º 1
0
 public void Add(MixAndVolume mixAndVolume)
 {
     Mix.Add(mixAndVolume.Mix);
     Volume = Volume + mixAndVolume.Volume;
     gasMix = gasMix + mixAndVolume.gasMix;
     gasMix.ChangeVolumeValue(mixAndVolume.gasMix.Volume);
 }
Ejemplo n.º 2
0
    public void Heartbeat(float efficiency)
    {
        CirculatorySystemBase circulatorySystem = RelatedPart.HealthMaster.CirculatorySystem;

        if (circulatorySystem)
        {
            float pumpedReagent    = Math.Min(heartStrength * efficiency, circulatorySystem.ReadyBloodPool.Total);
            float totalWantedBlood = 0;
            foreach (BodyPart implant in RelatedPart.HealthMaster.ImplantList)
            {
                if (implant.IsBloodCirculated == false)
                {
                    continue;
                }
                totalWantedBlood += implant.BloodThroughput;
            }

            pumpedReagent = Math.Min(pumpedReagent, totalWantedBlood);
            ReagentMix SpareBlood = new ReagentMix();

            foreach (BodyPart implant in RelatedPart.HealthMaster.ImplantList)
            {
                if (implant.IsBloodCirculated == false)
                {
                    continue;
                }
                var BloodToGive = circulatorySystem.ReadyBloodPool.Take((implant.BloodThroughput / totalWantedBlood) * pumpedReagent);
                BloodToGive.Add(SpareBlood);
                SpareBlood.Clear();
                SpareBlood.Add(implant.BloodPumpedEvent(BloodToGive));
            }

            circulatorySystem.ReadyBloodPool.Add(SpareBlood);
        }
    }
Ejemplo n.º 3
0
        /// <summary>
        /// Takes gases from a GasMix and puts them into blood as a reagent
        /// </summary>
        public void GasExchangeToBlood(GasMix atmos, ReagentMix blood, ReagentMix toProcess, float LungCapacity)
        {
            lock (toProcess.reagents)
            {
                foreach (var Reagent in toProcess.reagents.m_dict)
                {
                    blood.Add(Reagent.Key, Reagent.Value);
                }
            }


            if (!canBreathAnywhere)
            {
                if (LungCapacity + 0.1f > atmos.Moles)                 //Just so scenario where there isn't Gas * 0 = 0
                {
                    atmos.MultiplyGas(0.01f);
                }
                else
                {
                    if (atmos.Moles == 0)
                    {
                        return;
                    }

                    var percentageRemaining = 1 - (LungCapacity / atmos.Moles);
                    atmos.MultiplyGas(percentageRemaining);
                }
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Expels unwanted gases from the blood stream into the given gas mix
        /// </summary>
        /// <param name="gasMix">The gas mix to breathe out into</param>
        /// <param name="blood">The blood to pull gases from</param>
        /// <returns> True if breathGasMix was changed </returns>
        private bool BreatheOut(GasMix gasMix, ReagentMix blood)
        {
            SpecialCarrier.Clear();
            var OptimalBloodGasCapacity = 0f;
            var BloodGasCapacity        = 0f;

            foreach (var Reagent in blood.reagents.m_dict)
            {
                var BloodType = Reagent.Key as BloodType;
                if (BloodType != null)
                {
                    OptimalBloodGasCapacity += Reagent.Value * BloodType.BloodCapacityOf;
                    BloodGasCapacity        += Reagent.Value * BloodType.BloodGasCapability;
                    SpecialCarrier.Add(BloodType.CirculatedReagent);
                    SpecialCarrier.Add(BloodType.WasteCarryReagent);
                }
            }

            // This isn't exactly realistic, should also factor concentration of gases in the gasMix
            ReagentMix toExhale = new ReagentMix();

            foreach (var reagent in blood.reagents.m_dict)
            {
                if (Gas.ReagentToGas.ContainsKey(reagent.Key) == false)
                {
                    continue;
                }

                if (reagent.Value <= 0)
                {
                    continue;
                }

                if (SpecialCarrier.Contains(reagent.Key))
                {
                    toExhale.Add(reagent.Key, (reagent.Value / OptimalBloodGasCapacity) * LungSize);
                }
                else
                {
                    toExhale.Add(reagent.Key, (reagent.Value / BloodGasCapacity) * LungSize);
                }
            }

            RelatedPart.HealthMaster.RespiratorySystem.GasExchangeFromBlood(gasMix, blood, toExhale);
            //Debug.Log("Gas exhaled: " + toExhale.Total);
            return(toExhale.Total > 0);
        }
        ///<summary>
        /// Adds a volume of blood along with the maximum normal reagents
        ///</summary>
        public void AddFreshBlood(ReagentMix bloodPool, float amount)
        {
            // Currently only does blood and required reagents, should at nutriments and other common gases
            var bloodToAdd = new ReagentMix(BloodType, amount);

            bloodToAdd.Add(CirculatedReagent, bloodType.GetGasCapacity(bloodToAdd));
            bloodPool.Add(bloodToAdd);
        }
Ejemplo n.º 6
0
 /// <summary>
 /// Takes gases from a GasMix and puts them into blood as a reagent
 /// </summary>
 public void GasExchangeToBlood(GasMix atmos, ReagentMix blood, ReagentMix toProcess)
 {
     foreach (var Reagent in toProcess)
     {
         blood.Add(Reagent.Key, Reagent.Value);
         if (!canBreathAnywhere)
         {
             atmos.RemoveGas(GAS2ReagentSingleton.Instance.GetReagentToGas(Reagent.Key), Reagent.Value);
         }
     }
 }
Ejemplo n.º 7
0
        public void Add(MixAndVolume mixAndVolume)
        {
            Mix.Add(mixAndVolume.Mix);
            Volume = Volume + mixAndVolume.Volume;
            gasMix = gasMix + mixAndVolume.gasMix;
            gasMix.ChangeVolumeValue(mixAndVolume.gasMix.Volume);

            if (gasMix.Gases.Any(x => x < 0))
            {
                Logger.Log("0!!!");
            }
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Takes initial values and scales them based on potency
        /// </summary>
        private void SetupChemicalContents()
        {
            ReagentMix CurrentReagentMix = new ReagentMix();

            foreach (var reagentAndAmount in plantData.ReagentProduction)
            {
                CurrentReagentMix.Add(reagentAndAmount.ChemistryReagent, reagentAndAmount.Amount);
            }

            reagentContainer.Add(CurrentReagentMix);

            reagentContainer.Multiply(plantData.Potency / 100f * 2.5f);               //40 Potency = * 1
        }
Ejemplo n.º 9
0
    /// <summary>
    /// Expels unwanted gases from the blood stream into the given gas mix
    /// </summary>
    /// <param name="gasMix">The gas mix to breathe out into</param>
    /// <param name="blood">The blood to pull gases from</param>
    /// <returns> True if breathGasMix was changed </returns>
    private bool BreatheOut(GasMix gasMix, ReagentMix blood, float efficiency)
    {
        // This isn't exactly realistic, should also factor concentration of gases in the gasMix
        ReagentMix toExhale = new ReagentMix();

        foreach (var Reagent in blood.reagents.m_dict)
        {
            if (GAS2ReagentSingleton.Instance.DictionaryReagentToGas.ContainsKey(Reagent.Key))
            {
                // Try to prevent lungs removing desired gases and non gases from blood.
                // May want to add other gases that the lungs are unable to remove as well (ie toxins)
                var gas = GAS2ReagentSingleton.Instance.GetReagentToGas(Reagent.Key);
                if (gas != requiredGas && Reagent.Value > 0)
                {
                    toExhale.Add(Reagent.Key, Reagent.Value * efficiency);
                }
                else if (gas == requiredGas && Reagent.Value > 0)
                {
                    float ratio;
                    if (gasMix.GetPressure(requiredGas) < pressureSafeMin)
                    {
                        ratio = 1 - gasMix.GetPressure(requiredGas) / pressureSafeMin;
                    }
                    else
                    {
                        // Will still lose required gas suspended in blood plasma
                        ratio = RelatedPart.bloodType.BloodGasCapability / RelatedPart.bloodType.BloodCapacityOf;
                    }

                    toExhale.Add(Reagent.Key, ratio * Reagent.Value * efficiency);
                }
            }
        }

        RelatedPart.HealthMaster.RespiratorySystem.GasExchangeFromBlood(gasMix, blood, toExhale);
        //Debug.Log("Gas exhaled: " + toExhale.Total);
        return(toExhale.Total > 0);
    }
Ejemplo n.º 10
0
    /// <summary>
    /// Pulls in the desired gas, as well as others, from the specified gas mix and adds them to the blood stream
    /// </summary>
    /// <param name="gasMix">The gas mix to breathe in from</param>
    /// <param name="blood">The blood to put gases into</param>
    /// <returns> True if breathGasMix was changed </returns>
    private bool BreatheIn(GasMix breathGasMix, ReagentMix blood, float efficiency)
    {
        if (healthMaster.RespiratorySystem.CanBreathAnywhere)
        {
            blood.Add(requiredReagent, bloodType.GetSpareGasCapacity(blood));
            return(false);
        }
        ReagentMix toInhale = new ReagentMix();

        for (int i = 0; i < breathGasMix.Gases.Length; i++)
        {
            if (GAS2ReagentSingleton.Instance.DictionaryGasToReagent.ContainsKey(Gas.All[i]))
            {
                // n = PV/RT
                float gasMoles = breathGasMix.GetPressure(Gas.All[i]) * LungSize / 8.314f / breathGasMix.Temperature;

                // Get as much as we need, or as much as in the lungs, whichever is lower
                Reagent gasReagent    = GAS2ReagentSingleton.Instance.GetGasToReagent(Gas.All[i]);
                float   molesRecieved = Mathf.Min(gasMoles, bloodType.GetSpareGasCapacity(blood, gasReagent));
                toInhale.Add(gasReagent, molesRecieved * efficiency);

                //TODO: Add pressureSafeMax check here, for hyperoxia
            }
        }
        healthMaster.RespiratorySystem.GasExchangeToBlood(breathGasMix, blood, toInhale);

        // Counterintuitively, in humans respiration is stimulated by pressence of CO2 in the blood, not lack of oxygen
        // May want to change this code to reflect that in the future so people don't hyperventilate when they are on nitrous oxide
        var inGas      = GAS2ReagentSingleton.Instance.GetGasToReagent(requiredGas);
        var saturation = (toInhale[inGas] + blood[inGas]) / bloodType.GetGasCapacity(blood);

        if (saturation >= HealthMaster.CirculatorySystem.BloodInfo.BLOOD_REAGENT_SATURATION_OKAY)
        {
            currentBreatheCooldown = breatheCooldown;             //Slow breathing, we're all good
            healthMaster.HealthStateController.SetSuffocating(false);
        }
        else if (saturation <= HealthMaster.CirculatorySystem.BloodInfo.BLOOD_REAGENT_SATURATION_BAD)
        {
            healthMaster.HealthStateController.SetSuffocating(true);
            if (Random.value < 0.2)
            {
                Chat.AddActionMsgToChat(gameObject, "You gasp for breath", $"{healthMaster.gameObject.ExpensiveName()} gasps");
            }
        }

        //Debug.Log("Gas inhaled: " + toInhale.Total + " Saturation: " + saturation);
        return(toInhale.Total > 0);
    }
Ejemplo n.º 11
0
    public void Heartbeat(float efficiency)
    {
        CirculatorySystemBase circulatorySystem = RelatedPart.HealthMaster.CirculatorySystem;

        if (circulatorySystem)
        {
            //circulatorySystem.HeartBeat(heartStrength * TotalModified);
            //TODOH Balance all this stuff, Currently takes an eternity to suffocate
            // Logger.Log("heart Available  " + ReadyBloodPool);
            // Logger.Log("heart pumpedReagent " + pumpedReagent);

            float totalWantedBlood = 0;
            foreach (BodyPart implant in RelatedPart.HealthMaster.ImplantList)
            {
                if (implant.IsBloodCirculated == false)
                {
                    continue;
                }
                totalWantedBlood += implant.BloodThroughput * efficiency;
                // Due to how blood is implemented as a single pool with its solutes, we need to compensate for
                // consumed solutes.  This may change in the future if blood changes
                totalWantedBlood += implant.BloodContainer.MaxCapacity - implant.BloodContainer.ReagentMixTotal;
            }
            float toPump      = Mathf.Min(totalWantedBlood, heartStrength * efficiency);
            var   bloodToGive = circulatorySystem.ReadyBloodPool.Take(Mathf.Min(toPump, circulatorySystem.ReadyBloodPool.Total));
            if (bloodToGive.Total < toPump)
            {
                // Try to maintain blood levels in organs by taking the remainder from used
                circulatorySystem.UsedBloodPool.TransferTo(bloodToGive, Mathf.Min(toPump - bloodToGive.Total, circulatorySystem.UsedBloodPool.Total));
            }

            ReagentMix SpareBlood = new ReagentMix();
            foreach (BodyPart implant in RelatedPart.HealthMaster.ImplantList)
            {
                if (implant.IsBloodCirculated == false)
                {
                    continue;
                }
                ReagentMix transfer = bloodToGive.Take((implant.BloodThroughput * efficiency + implant.BloodContainer.MaxCapacity
                                                        - implant.BloodContainer.ReagentMixTotal) / totalWantedBlood * bloodToGive.Total);
                transfer.Add(SpareBlood);
                SpareBlood.Clear();
                SpareBlood.Add(implant.BloodPumpedEvent(transfer, efficiency));
            }
            circulatorySystem.ReadyBloodPool.Add(SpareBlood);
            circulatorySystem.ReadyBloodPool.Add(bloodToGive);
        }
    }
Ejemplo n.º 12
0
    public virtual void PossibleReaction(BodyPart sender, ReagentMix reagentMix, float limitedreactionAmount)
    {
        foreach (var ingredient in ingredients.m_dict)
        {
            reagentMix.Subtract(ingredient.Key, limitedreactionAmount * ingredient.Value);
        }

        foreach (var result in results.m_dict)
        {
            var reactionResult = limitedreactionAmount * result.Value;
            reagentMix.Add(result.Key, reactionResult);
        }

        foreach (var effect in effects)
        {
            effect.Apply(sender, limitedreactionAmount);
        }
    }
Ejemplo n.º 13
0
        public void Add(MixAndVolume mixAndVolume, bool ChangeVolume = true)
        {
            float internalEnergy = mixAndVolume.InternalEnergy + this.InternalEnergy;
            float GasVolume      = gasMix.Volume;

            if (ChangeVolume)
            {
                GasVolume = GasVolume + mixAndVolume.gasMix.Volume;
            }

            Mix.Add(mixAndVolume.Mix);
            var Newone = new float[gasMix.Gases.Length];

            for (int i = 0; i < gasMix.Gases.Length; i++)
            {
                Newone[i] = gasMix.Gases[i] + mixAndVolume.gasMix.Gases[i];
            }

            gasMix = GasMix.FromTemperature(Newone, gasMix.Temperature, GasVolume);
            this.InternalEnergy = internalEnergy;
        }
Ejemplo n.º 14
0
    /// <summary>
    /// Release reagents at provided coordinates, making them react with world
    /// </summary>
    public void ReagentReact(ReagentMix reagents, Vector3Int worldPosInt, Vector3Int localPosInt)
    {
        if (MatrixManager.IsTotallyImpassable(worldPosInt, true))
        {
            return;
        }

        bool didSplat   = false;
        bool paintBlood = false;

        //Find all reagents on this tile (including current reagent)
        var reagentContainer = MatrixManager.GetAt <ReagentContainer>(worldPosInt, true);
        var existingSplats   = MatrixManager.GetAt <FloorDecal>(worldPosInt, true);

        for (var i = 0; i < existingSplats.Count; i++)
        {
            if (existingSplats[i].GetComponent <ReagentContainer>())
            {
                existingSplat = existingSplats[i];
            }
        }

        //Loop though all reagent containers and add the passed in reagents
        foreach (ReagentContainer chem in reagentContainer)
        {
            //If the reagent tile is a pool/puddle/splat
            if (chem.ExamineAmount == ReagentContainer.ExamineAmountMode.UNKNOWN_AMOUNT)
            {
                reagents.Add(chem.CurrentReagentMix);
            }
            //TODO: could allow you to add this to other container types like beakers but would need some balance and perhaps knocking over the beaker
        }

        if (reagents.Total > 0)
        {
            //Force clean the tile
            Clean(worldPosInt, localPosInt, false);

            lock (reagents.reagents)
            {
                foreach (var reagent in reagents.reagents.m_dict)
                {
                    switch (reagent.Key.name)
                    {
                    case "HumanBlood":
                    {
                        paintBlood = true;
                        break;
                    }

                    case "Water":
                    {
                        MakeSlipperyAt(localPosInt);
                        matrix.ReactionManager.ExtinguishHotspot(localPosInt);
                        foreach (var livingHealthBehaviour in matrix.Get <LivingHealthMasterBase>(localPosInt, true))
                        {
                            livingHealthBehaviour.Extinguish();
                        }
                        break;
                    }

                    case "SpaceCleaner":
                        Clean(worldPosInt, localPosInt, false);
                        didSplat = true;
                        break;

                    case "SpaceLube":
                    {
                        // ( ͡° ͜ʖ ͡°)
                        if (Get(localPosInt).IsSlippery == false)
                        {
                            EffectsFactory.WaterSplat(worldPosInt);
                            MakeSlipperyAt(localPosInt, false);
                        }
                        break;
                    }

                    default:
                        break;
                    }
                }
            }

            if (didSplat == false)
            {
                if (paintBlood)
                {
                    PaintBlood(worldPosInt, reagents);
                }
                else
                {
                    Paintsplat(worldPosInt, localPosInt, reagents);
                }
            }
        }
    }
Ejemplo n.º 15
0
    /// <summary>
    /// Pulls in the desired gas, as well as others, from the specified gas mix and adds them to the blood stream
    /// </summary>
    /// <param name="gasMix">The gas mix to breathe in from</param>
    /// <param name="blood">The blood to put gases into</param>
    /// <returns> True if breathGasMix was changed </returns>
    private bool BreatheIn(GasMix breathGasMix, ReagentMix blood, float efficiency)
    {
        if (RelatedPart.HealthMaster.RespiratorySystem.CanBreathAnywhere)
        {
            blood.Add(RelatedPart.requiredReagent, RelatedPart.bloodType.GetSpareGasCapacity(blood));
            return(false);
        }

        ReagentMix toInhale   = new ReagentMix();
        var        Available  = RelatedPart.bloodType.GetGasCapacityOfnonMeanCarrier(blood);
        var        TotalMoles = breathGasMix.Moles;

        ToxinBreathinCheck(breathGasMix);
        foreach (var gasValues in breathGasMix.GasData.GasesArray)
        {
            var gas = gasValues.GasSO;
            if (GAS2ReagentSingleton.Instance.DictionaryGasToReagent.ContainsKey(gas) == false)
            {
                continue;
            }

            // n = PV/RT
            float gasMoles = breathGasMix.GetMoles(gas);

            // Get as much as we need, or as much as in the lungs, whichever is lower
            Reagent gasReagent    = GAS2ReagentSingleton.Instance.GetGasToReagent(gas);
            float   molesRecieved = 0;
            if (gasReagent == RelatedPart.bloodType.CirculatedReagent)
            {
                molesRecieved = Mathf.Min(gasMoles, RelatedPart.bloodType.GetSpareGasCapacity(blood, gasReagent));
            }
            else
            {
                if (gasMoles == 0)
                {
                    molesRecieved = 0;
                }
                else
                {
                    molesRecieved = Available / (TotalMoles / gasMoles);
                    molesRecieved = Mathf.Min(molesRecieved, gasMoles);
                }
            }

            if (molesRecieved > 0)
            {
                toInhale.Add(gasReagent, molesRecieved * efficiency);
            }

            //TODO: Add pressureSafeMax check here, for hyperoxia
        }

        RelatedPart.HealthMaster.RespiratorySystem.GasExchangeToBlood(breathGasMix, blood, toInhale);

        // Counterintuitively, in humans respiration is stimulated by pressence of CO2 in the blood, not lack of oxygen
        // May want to change this code to reflect that in the future so people don't hyperventilate when they are on nitrous oxide
        var   inGas           = GAS2ReagentSingleton.Instance.GetGasToReagent(requiredGas);
        float bloodCap        = RelatedPart.bloodType.GetGasCapacity(RelatedPart.BloodContainer.CurrentReagentMix);
        float foreignCap      = RelatedPart.bloodType.GetGasCapacityForeign(RelatedPart.BloodContainer.CurrentReagentMix);
        float bloodSaturation = 0;

        if (bloodCap + foreignCap == 0)
        {
            bloodSaturation = 0;
        }
        else
        {
            var ratioNativeBlood = bloodCap / (bloodCap + foreignCap);
            bloodSaturation = RelatedPart.BloodContainer[RelatedPart.requiredReagent] * ratioNativeBlood / bloodCap;
        }

        if (bloodSaturation >= RelatedPart.HealthMaster.CirculatorySystem.BloodInfo.BLOOD_REAGENT_SATURATION_OKAY)
        {
            currentBreatheCooldown = breatheCooldown;             //Slow breathing, we're all good
            RelatedPart.HealthMaster.HealthStateController.SetSuffocating(false);
        }
        else if (bloodSaturation <= RelatedPart.HealthMaster.CirculatorySystem.BloodInfo.BLOOD_REAGENT_SATURATION_BAD)
        {
            RelatedPart.HealthMaster.HealthStateController.SetSuffocating(true);
            if (Random.value < 0.2)
            {
                Chat.AddActionMsgToChat(RelatedPart.HealthMaster.gameObject, "You gasp for breath",
                                        $"{RelatedPart.HealthMaster.playerScript.visibleName} gasps");
            }
        }

        //Debug.Log("Gas inhaled: " + toInhale.Total + " Saturation: " + saturation);
        return(toInhale.Total > 0);
    }
Ejemplo n.º 16
0
        /// <summary>
        /// Pulls in the desired gas, as well as others, from the specified gas mix and adds them to the blood stream
        /// </summary>
        /// <param name="gasMix">The gas mix to breathe in from</param>
        /// <param name="blood">The blood to put gases into</param>
        /// <returns> True if breathGasMix was changed </returns>
        private bool BreatheIn(GasMix breathGasMix, ReagentMix blood, float efficiency)
        {
            if (RelatedPart.HealthMaster.RespiratorySystem.CanBreatheAnywhere)
            {
                blood.Add(RelatedPart.requiredReagent, RelatedPart.bloodType.GetSpareGasCapacity(blood));
                return(false);
            }

            ReagentMix toInhale  = new ReagentMix();
            var        Available = RelatedPart.bloodType.GetNormalGasCapacity(blood);

            ToxinBreathinCheck(breathGasMix);
            float PercentageCanTake = 1;

            if (breathGasMix.Moles != 0)
            {
                PercentageCanTake = LungSize / breathGasMix.Moles;
            }

            if (PercentageCanTake > 1)
            {
                PercentageCanTake = 1;
            }

            var PressureMultiplier = breathGasMix.Pressure / pressureSafeMin;

            if (PressureMultiplier > 1)
            {
                PressureMultiplier = 1;
            }

            var TotalMoles = breathGasMix.Moles * PercentageCanTake;


            lock (breathGasMix.GasData.GasesArray)             //no Double lock
            {
                foreach (var gasValues in breathGasMix.GasData.GasesArray)
                {
                    var gas = gasValues.GasSO;
                    if (Gas.GasToReagent.TryGetValue(gas, out var gasReagent) == false)
                    {
                        continue;
                    }

                    // n = PV/RT
                    float gasMoles = breathGasMix.GetMoles(gas) * PercentageCanTake;

                    // Get as much as we need, or as much as in the lungs, whichever is lower
                    float molesRecieved = 0;

                    if (gasReagent == RelatedPart.bloodType.CirculatedReagent)
                    {
                        var PercentageMultiplier = (gasMoles / (TotalMoles));
                        molesRecieved = RelatedPart.bloodType.GetSpecialGasCapacity(blood) * PercentageMultiplier *
                                        PressureMultiplier;
                    }
                    else if (gasMoles != 0)
                    {
                        molesRecieved = (Available * (gasMoles / TotalMoles)) * PressureMultiplier;
                    }

                    if (molesRecieved > 0)
                    {
                        toInhale.Add(gasReagent, molesRecieved);
                    }
                }
            }

            RelatedPart.HealthMaster.RespiratorySystem.GasExchangeToBlood(breathGasMix, blood, toInhale, LungSize);


            // Counterintuitively, in humans respiration is stimulated by pressence of CO2 in the blood, not lack of oxygen
            // May want to change this code to reflect that in the future so people don't hyperventilate when they are on nitrous oxide
            float bloodCap        = RelatedPart.bloodType.GetNormalGasCapacity(RelatedPart.BloodContainer.CurrentReagentMix);
            var   bloodSaturation = 0f;

            if (bloodCap > 0)
            {
                bloodSaturation = RelatedPart.BloodContainer[RelatedPart.requiredReagent] / bloodCap;
            }

            if (bloodSaturation >= RelatedPart.HealthMaster.CirculatorySystem.BloodInfo.BLOOD_REAGENT_SATURATION_OKAY)
            {
                currentBreatheCooldown = breatheCooldown;                 //Slow breathing, we're all good
                RelatedPart.HealthMaster.HealthStateController.SetSuffocating(false);
            }
            else if (bloodSaturation <= RelatedPart.HealthMaster.CirculatorySystem.BloodInfo.BLOOD_REAGENT_SATURATION_BAD)
            {
                RelatedPart.HealthMaster.HealthStateController.SetSuffocating(true);
                if (DMMath.Prob(20))
                {
                    Chat.AddActionMsgToChat(RelatedPart.HealthMaster.gameObject, "You gasp for breath!",
                                            $"{RelatedPart.HealthMaster.playerScript.visibleName} gasps!");
                }
            }

            //Debug.Log("Gas inhaled: " + toInhale.Total + " Saturation: " + saturation);
            return(toInhale.Total > 0);
        }