private float HandleBreathing(GasMix breathGasMix) { float oxygenPressure = breathGasMix.GetPressure(Gas.Oxygen); float oxygenUsed = 0; if (oxygenPressure < OXYGEN_SAFE_MIN) { if (Random.value < 0.2) { PostToChatMessage.Send("gasp", ChatChannel.Local); } if (oxygenPressure > 0) { float ratio = 1 - oxygenPressure / OXYGEN_SAFE_MIN; ApplyDamage(Mathf.Min(5 * ratio, 3), DamageType.Oxy); bloodSystem.OxygenLevel += 30 * ratio; oxygenUsed = breathGasMix.GetMoles(Gas.Oxygen) * ratio; } else { ApplyDamage(3, DamageType.Oxy); } } else { oxygenUsed = breathGasMix.GetMoles(Gas.Oxygen); bloodSystem.OxygenLevel += 30; } return(oxygenUsed); }
private float HandleBreathing(GasMix breathGasMix) { float oxygenPressure = breathGasMix.GetPressure(Gas.Oxygen); float oxygenUsed = 0; if (oxygenPressure < OXYGEN_SAFE_MIN) { if (Random.value < 0.1) { Chat.AddActionMsgToChat(gameObject, "You gasp for breath", $"{gameObject.name} gasps"); } if (oxygenPressure > 0) { float ratio = 1 - oxygenPressure / OXYGEN_SAFE_MIN; bloodSystem.OxygenDamage += 1 * ratio; oxygenUsed = breathGasMix.GetMoles(Gas.Oxygen) * ratio; } else { bloodSystem.OxygenDamage += 1; } IsSuffocating = true; } else { oxygenUsed = breathGasMix.GetMoles(Gas.Oxygen); IsSuffocating = false; bloodSystem.OxygenDamage -= 2.5f; breatheCooldown = 4; } return(oxygenUsed); }
private float HandleBreathing(GasMix breathGasMix) { float oxygenPressure = breathGasMix.GetPressure(Gas.Oxygen); float oxygenUsed = 0; if (oxygenPressure < OXYGEN_SAFE_MIN) { if (Random.value < 0.1) { PostToChatMessage.SendGasp(base.gameObject); } if (oxygenPressure > 0) { float ratio = 1 - oxygenPressure / OXYGEN_SAFE_MIN; bloodSystem.OxygenDamage += 1 * ratio; oxygenUsed = breathGasMix.GetMoles(Gas.Oxygen) * ratio; } else { bloodSystem.OxygenDamage += 1; } IsSuffocating = true; } else { oxygenUsed = breathGasMix.GetMoles(Gas.Oxygen); IsSuffocating = false; bloodSystem.OxygenDamage -= 2.5f; breatheCooldown = 4; } return(oxygenUsed); }
/// <summary> /// Placeholder method to add some effects for breathing plasma. Eventually this behavior should be /// handled with interfaces we can implement so different species react differently. /// </summary> /// <param name="plasmaAmount"></param> private float HandleBreathingPlasma(GasMix gasMix) { float plasmaPressure = gasMix.GetPressure(Gas.Plasma); float plasmaConsumed = 0; plasmaConsumed = gasMix.GetMoles(Gas.Plasma) * AtmosConstants.BREATH_VOLUME; // there is some plasma in the ambient but it is still safe if (plasmaPressure <= PLASMA_SAFE_MAX && plasmaPressure > PLASMA_WARNING_LEVEL) { if (DMMath.Prob(90)) { return(plasmaConsumed); } // 10% chances of message var theirPronoun = gameObject.Player() != null ? gameObject.Player().Script.characterSettings.TheirPronoun(gameObject.Player().Script) : "its"; Chat.AddActionMsgToChat( gameObject, plasmaLowYouMessages.PickRandom(), string.Format( plasmaLowOthersMessages.PickRandom(), gameObject.ExpensiveName(), string.Format(plasmaLowOthersMessages.PickRandom(), gameObject.ExpensiveName(), theirPronoun)) ); } // enough plasma to be visible and damage us! else if (plasmaPressure > PLASMA_SAFE_MAX) { var plasmaDamage = (gasMix.GetMoles(Gas.Plasma) / PLASMA_SAFE_MAX) * 10; bloodSystem.ToxinLevel = Mathf.Clamp(bloodSystem.ToxinLevel + Mathf.Clamp(plasmaDamage, MIN_TOXIN_DMG, MAX_TOXIN_DMG), 0, 200); if (DMMath.Prob(90)) { return(plasmaConsumed); } // 10% chances of message var theirPronoun = gameObject.Player() != null ? gameObject.Player().Script.characterSettings.TheirPronoun(gameObject.Player().Script) : "its"; Chat.AddActionMsgToChat( gameObject, plasmaHighYouMessages.PickRandom(), string.Format(plasmaHighOthersMessages.PickRandom(), gameObject.ExpensiveName(), theirPronoun) ); } return(plasmaConsumed); }
/// <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); }
/// <summary> /// Checks for toxic gases and if they excede their maximum range before they become deadly /// </summary> /// <param name="gasMix">the gases the character is breathing in</param> public virtual void ToxinBreathinCheck(GasMix gasMix) { if (RelatedPart.HealthMaster.RespiratorySystem.CanBreatheAnywhere || RelatedPart.HealthMaster.playerScript == null) return; foreach (ToxicGas gas in toxicGases) { float pressure = gasMix.GetPressure(gas.GasType); if (pressure >= gas.PressureSafeMax) { RelatedPart.HealthMaster.RespiratorySystem.ApplyDamage(gas.UnsafeLevelDamage, gas.UnsafeLevelDamageType); } } }
/// <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); }
private float HandleBreathing(GasMix gasMix) { float oxygenPressure = gasMix.GetPressure(Gas.Oxygen); float plasmaAmount = gasMix.GetMoles(Gas.Plasma); float oxygenUsed = 0; if (plasmaAmount > 0) { HandleBreathingPlasma(plasmaAmount); } if (oxygenPressure < OXYGEN_SAFE_MIN) { if (Random.value < 0.1) { Chat.AddActionMsgToChat(gameObject, "You gasp for breath", $"{gameObject.ExpensiveName()} gasps"); } if (oxygenPressure > 0) { float ratio = 1 - oxygenPressure / OXYGEN_SAFE_MIN; bloodSystem.OxygenDamage += 1 * ratio; oxygenUsed = gasMix.GetMoles(Gas.Oxygen) * ratio * AtmosConstants.BREATH_VOLUME; } else { bloodSystem.OxygenDamage += 1; } IsSuffocating = true; } else { oxygenUsed = gasMix.GetMoles(Gas.Oxygen) * AtmosConstants.BREATH_VOLUME; IsSuffocating = false; bloodSystem.OxygenDamage -= 2.5f; breatheCooldown = 4; } return(oxygenUsed); }
private IEnumerator Breathe() { while (!health.IsDead) { MetaDataLayer metaDataLayer = MatrixManager.AtPoint(Vector3Int.RoundToInt(transform.position)).MetaDataLayer; GasMix atmos = metaDataLayer.Get(transform.localPosition.RoundToInt(), false).Atmos; float partialPressure = atmos.GetPressure(Gas.Oxygen); if (partialPressure < AtmosConstants.MINIMUM_OXYGEN_PRESSURE) { float ratio = 1 - partialPressure / AtmosConstants.MINIMUM_OXYGEN_PRESSURE; Logger.Log("URGENT TODO: Move this to LivingHealthBehaviour Respiratory system ", Category.Health); //health.ApplyDamage(null, Mathf.Min(5 * ratio, 3), DamageType.Oxy); } else { // TODO implement breathing (remove oxygen, add co2, etc.) } yield return(new WaitForSeconds(breathTime)); } }
private bool HandleBreathingCarbonDioxide(GasMix gasMix) { float carbonPressure = gasMix.GetPressure(Gas.CarbonDioxide); // there is a little carbon dioxide in the air. if (carbonPressure <= CARBON_DIOXIDE_SAFE_MAX && carbonPressure > CARBON_DIOXIDE_WARNING_LEVEL) { if (DMMath.Prob(90)) { return(true); } // 10% chances of message var theirPronoun = gameObject.Player() != null ? gameObject.Player().Script.characterSettings.TheirPronoun(gameObject.Player().Script) : "its"; Chat.AddActionMsgToChat( gameObject, CO2LowYouMessages.PickRandom(), string.Format( CO2LowOthersMessages.PickRandom(), gameObject.ExpensiveName(), string.Format(plasmaLowOthersMessages.PickRandom(), gameObject.ExpensiveName(), theirPronoun)) ); } // enough carbon dioxide to start suffocating you! else if (carbonPressure > CARBON_DIOXIDE_SAFE_MAX) { if (CarbonSuffocationTimer >= 0) { CarbonSuffocationTimer++; } if (CarbonSuffocationTimer >= 3 && CarbonSuffocationTimer < 7) { IsSuffocating = true; bloodSystem.OxygenDamage += 3; if (DMMath.Prob(90)) { return(true); } // 10% chances of message var theirPronoun = gameObject.Player() != null ? gameObject.Player().Script.characterSettings.TheirPronoun(gameObject.Player().Script) : "its"; Chat.AddActionMsgToChat( gameObject, CO2MedYouMessages.PickRandom(), string.Format(CO2MedOthersMessages.PickRandom(), gameObject.ExpensiveName(), theirPronoun) ); } else if (CarbonSuffocationTimer >= 7) { IsSuffocating = true; bloodSystem.OxygenDamage += 8; if (DMMath.Prob(90)) { return(true); } // 10% chances of message var theirPronoun = gameObject.Player() != null ? gameObject.Player().Script.characterSettings.TheirPronoun(gameObject.Player().Script) : "its"; Chat.AddActionMsgToChat( gameObject, CO2HighYouMessages.PickRandom(), string.Format(CO2HighOthersMessages.PickRandom(), gameObject.ExpensiveName(), theirPronoun) ); return(true); } } if (carbonPressure < CARBON_DIOXIDE_WARNING_LEVEL) { CarbonSuffocationTimer = 0; return(carbonPressure > 0); } return(false); }
/// <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; 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.GetPressure(gas) * 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); 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.Approx(0) == false) { 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.PlayerScriptOwner.visibleName} gasps"); } } //Debug.Log("Gas inhaled: " + toInhale.Total + " Saturation: " + saturation); return(toInhale.Total > 0); }