public void Add(MixAndVolume mixAndVolume) { Mix.Add(mixAndVolume.Mix); Volume = Volume + mixAndVolume.Volume; gasMix = gasMix + mixAndVolume.gasMix; gasMix.ChangeVolumeValue(mixAndVolume.gasMix.Volume); }
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); } }
/// <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); } } }
/// <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); }
/// <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); } } }
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!!!"); } }
/// <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 }
/// <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> /// 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); }
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); } }
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); } }
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; }
/// <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); } } } }
/// <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); }
/// <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); }