public void Paintsplat(Vector3Int worldPosInt, Vector3Int localPosInt, ReagentMix reagents) { switch (ChemistryUtils.GetMixStateDescription(reagents)) { case "powder": { EffectsFactory.PowderSplat(worldPosInt, reagents.MixColor, reagents); break; } case "liquid": { //TODO: Work out if reagent is "slippery" according to its viscocity (not modeled yet) EffectsFactory.ChemSplat(worldPosInt, reagents.MixColor, reagents); break; } case "gas": //TODO: Make gas reagents release into the atmos. break; default: { EffectsFactory.ChemSplat(worldPosInt, reagents.MixColor, reagents); break; } } }
public void Bleed(float amount) { var bloodLoss = new ReagentMix(); ReadyBloodPool.TransferTo(bloodLoss, amount); MatrixManager.ReagentReact(bloodLoss, healthMaster.gameObject.RegisterTile().WorldPositionServer); }
/// <summary> /// Performs the action of breathing, expelling waste products from the used blood pool and refreshing /// the desired blood reagent (ie oxygen) /// </summary> /// <param name="node">The gas node at this lung's position</param> /// <returns>True if gas was exchanged</returns> public bool TryBreathing(IGasMixContainer node, float efficiency) { //Base effeciency is a little strong on the lungs //efficiency = (1 + efficiency) / 2; //Breathing is not timebased, but tick based, it will be slow when the blood has all the oxygen it needs //and will speed up if more oxygen is needed currentBreatheCooldown--; if (currentBreatheCooldown > 0) { return(false); } if (healthMaster.CirculatorySystem.UsedBloodPool[bloodType] == 0) { return(false); //No point breathing if we dont have blood. } // Try to get internal breathing if possible, otherwise get from the surroundings IGasMixContainer container = healthMaster.RespiratorySystem.GetInternalGasMix() ?? node; ReagentMix AvailableBlood = healthMaster.CirculatorySystem.UsedBloodPool.Take(healthMaster.CirculatorySystem.UsedBloodPool.Total); bool tryExhale = BreatheOut(container.GasMix, AvailableBlood, efficiency); bool tryInhale = BreatheIn(container.GasMix, AvailableBlood, efficiency); healthMaster.CirculatorySystem.ReadyBloodPool.Add(AvailableBlood); return(tryExhale || tryInhale); }
private void Milk(GameObject performer, ReagentContainer container) { if (currentMilkAmount < milkAmount) { onMilkedEmpty?.Invoke(performer, gameObject); mood.UpdateLevel(moodPenalty * -1); Chat.AddActionMsgToChat( performer, string.Format(noMilkMessage, performer.ExpensiveName(), mobAI.mobName.Capitalize()), "" ); return; } Chat.AddActionMsgToChat( performer, string.Format(milkMessageYou, mobAI.mobName.Capitalize()), string.Format(milkMessageOthers, mobAI.mobName.Capitalize(), performer.ExpensiveName()) ); currentMilkAmount -= milkAmount; var milkyMix = new ReagentMix(milkReagent, milkAmount, 40f); container.Add(milkyMix); }
/// <summary> /// This is called whenever blood is pumped through the circulatory system by a heartbeat. /// Can happen multiple times if there's multiple hearts. Pushes out old blood and brings /// in new blood, up to the part's capacity. /// </summary> /// <param name="bloodIn">Incoming blood</param> /// <returns>Whatever is left over from bloodIn</returns> public ReagentMix BloodPumpedEvent(ReagentMix bloodIn) { //Maybe have a dynamic 50% other blood in this blood // if (bloodReagent != requiredReagent) // { // return HandleWrongBloodReagent(bloodReagent, amountOfBloodReagentPumped); // } //bloodReagent.Subtract() //BloodContainer.Add(bloodReagent); //Maybe have damage from high/low blood levels and high blood pressure BloodContainer.CurrentReagentMix.TransferTo(HealthMaster.CirculatorySystem.UsedBloodPool, float.MaxValue); if ((BloodContainer.ReagentMixTotal + bloodIn.Total) > BloodContainer.MaxCapacity) { float BloodToTake = BloodContainer.MaxCapacity - BloodContainer.ReagentMixTotal; bloodIn.TransferTo(BloodContainer.CurrentReagentMix, BloodToTake); } else { bloodIn.TransferTo(BloodContainer.CurrentReagentMix, bloodIn.Total); } BloodContainer.OnReagentMixChanged?.Invoke(); BloodContainer.ReagentsChanged(); BloodWasPumped(); return(bloodIn); }
/// <summary> /// Updates contents of Container Page with current list of reagents and amounts, and provides /// feedback if there is a lack of reagents or container /// </summary> public void DisplayContainerReagents() { if (ChemMaster.Container) { if (ChemMaster.Container.CurrentReagentMix.Total != 0) { ReagentMix tempMix = ChemMaster.Container.CurrentReagentMix; containerList.Clear(); containerList.SetItems(tempMix.reagents.Count); int i = 0; foreach (Reagent reagent in tempMix.reagents.Keys) { GUI_ChemContainerEntry thing = containerList.Entries[i] as GUI_ChemContainerEntry; thing.ReInit(reagent, tempMix.reagents[reagent], GetComponent <GUI_ChemMaster>()); i++; } containerNoReagent.SetValueServer(""); } else { containerList.Clear(); containerNoReagent.SetValueServer("No Reagents in Container"); } //we have a container that is capable of being ejected ejectandClear.SetValueServer("true"); } else { containerList.Clear(); containerNoReagent.SetValueServer("No container"); ejectandClear.SetValueServer("false"); } }
public override void InternalDamageLogic() { if (!onCooldown) { if (RelatedPart.CurrentInternalBleedingDamage > RelatedPart.MaximumInternalBleedDamage / 2) { Chat.AddActionMsgToChat(RelatedPart.HealthMaster.gameObject, "You gasp for air; but you drown in your own blood from the inside!", $"{RelatedPart.HealthMaster.playerScript.visibleName} gasps for air!"); RelatedPart.HealthMaster.HealthStateController.SetSuffocating(true); } else { RelatedPart.InternalBleedingLogic(); } if (DMMath.Prob(coughChanceWhenInternallyBleeding)) { Chat.AddActionMsgToChat(RelatedPart.HealthMaster.gameObject, "You cough up blood!", $"{RelatedPart.HealthMaster.playerScript.visibleName} coughs up blood!"); RelatedPart.CurrentInternalBleedingDamage -= 4; //TODO: TAKE BLOOD var bloodLoss = new ReagentMix(); RelatedPart.HealthMaster.CirculatorySystem.ReadyBloodPool.TransferTo(bloodLoss, RelatedPart.CurrentInternalBleedingDamage); MatrixManager.ReagentReact(bloodLoss, RelatedPart.HealthMaster.gameObject.RegisterTile().WorldPositionServer); } onCooldown = true; StartCoroutine(CooldownTick()); } }
/// <summary> /// Updates contents of Buffer Page with current list of reagents and amounts, and provides /// feedback if there is a lack of reagents or containers /// </summary> public void DisplayBufferReagents() { if (ChemMaster.GetBufferMix() != null) { ReagentMix tempMix = ChemMaster.GetBufferMix(); bufferList.Clear(); bufferList.SetItems(tempMix.reagents.Count); int i = 0; foreach (Reagent reagent in tempMix.reagents.Keys) { GUI_ChemBufferEntry thing = bufferList.Entries[i] as GUI_ChemBufferEntry; thing.ReInit(reagent, tempMix.reagents[reagent], GetComponent <GUI_ChemMaster>()); i++; } bufferNoReagent.SetValueServer(""); } else { bufferList.Clear(); if (!ChemMaster.BufferslotOne && !ChemMaster.BufferslotTwo) { bufferNoReagent.SetValueServer("No containers in buffer"); } else { bufferNoReagent.SetValueServer("No reagents in buffer"); } } }
/// <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); } } }
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); } }
public static void PowderSplat(Vector3Int worldPos, Color color, ReagentMix reagents) { EnsureInit(); var powderTileInst = Spawn.ServerPrefab(powderTile, worldPos, MatrixManager.AtPoint(worldPos, true).Objects, Quaternion.identity); if (powderTileInst.Successful) { var powderTileGO = powderTileInst.GameObject; var tileReagents = powderTileGO.GetComponent <ReagentContainer>(); var colorDesc = TextUtils.ColorToString(reagents.MixColor); var stateDesc = ChemistryUtils.GetMixStateDescription(reagents); powderTileInst.GameObject.name = $"{colorDesc} {stateDesc}"; if (powderTileGO) { var decal = powderTileGO.GetComponent <FloorDecal>(); if (decal) { decal.color = color; } if (reagents != null) { tileReagents.Add(reagents); } } } }
///<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); }
public float GetGasCapacity(ReagentMix reagentMix, Reagent reagent = null) { if (reagent == CirculatedReagent || reagent == null) { return(reagentMix[this] * BloodCapacityOf); } return(reagentMix[this] * BloodGasCapability); }
public float GetGasCapacity(ReagentMix reagentMix, Reagent reagent) { if (reagent == CirculatedReagent || reagent == null) { return(GetNormalGasCapacity(reagentMix)); } return(GetSpecialGasCapacity(reagentMix)); }
public float GetSpareGasCapacity(ReagentMix reagentMix, Reagent reagent = null) { if (reagent == CirculatedReagent || reagent == null) { return(GetGasCapacity(reagentMix) - reagentMix[CirculatedReagent]); } return(GetGasCapacity(reagentMix, reagent) - reagentMix[reagent]); }
private static ReagentContainer GetContainer(int maxCapacity, ReagentMix contents) { var set = ScriptableObject.CreateInstance <ReactionSet>(); var container = ReagentContainer.Create(set, maxCapacity); container.Add(contents); return(container); }
public override bool Apply(MonoBehaviour sender, ReagentMix reagentMix) { if (tempMin != null && reagentMix.Temperature <= tempMin || tempMax != null && reagentMix.Temperature >= tempMax) { return(false); } if (!ingredients.All(reagent => reagentMix[reagent.Key] > 0)) { return(false); } if (!ingredients.Any()) { return(false); } var reactionAmount = ingredients.Min(i => reagentMix[i.Key] / i.Value); if (useExactAmounts == true) { reactionAmount = (float)Math.Floor(reactionAmount); if (reactionAmount == 0) { return(false); } } if (!catalysts.All(catalyst => reagentMix[catalyst.Key] >= catalyst.Value * reactionAmount)) { return(false); } if (inhibitors.Count > 0) { if (inhibitors.All(inhibitor => reagentMix[inhibitor.Key] > inhibitor.Value * reactionAmount)) { return(false); } } var BodyPart = sender.GetComponent <BodyPart>(); if (BodyPart == null) { return(false); } BodyPart.MetabolismReactions.Add(this); return(false); }
/// <summary> /// Heals damage caused by lack of blood reagent by consume reagent /// </summary> /// <param name="reagentMix">Reagent mix to consume reagent from</param> /// <param name="amount">Amount to consume</param> public void OxyHeal(ReagentMix reagentMix, float amount) { if (Oxy <= 0) { return; } var toConsume = Mathf.Min(amount, Oxy * bloodReagentConsumed * bloodThroughput); AffectDamage(-reagentMix.Subtract(requiredReagent, toConsume) / bloodReagentConsumed * bloodThroughput, (int)DamageType.Oxy); }
public void React(BodyPart sender, ReagentMix reagentMix, float inReactionAmount) { var reactionAmount = GetReactionAmount(reagentMix); if ((reactionAmount / reagentMix.Total) < MinimumPercentageThreshold) { return; } PossibleReaction(sender, reagentMix, reactionAmount); }
/// <summary> /// Takes reagents from blood and puts them into a GasMix as gases /// </summary> public void GasExchangeFromBlood(GasMix atmos, ReagentMix blood, ReagentMix toProcess) { foreach (var Reagent in toProcess.reagents.m_dict) { blood.Remove(Reagent.Key, Reagent.Value); if (!canBreathAnywhere) { atmos.AddGas(GAS2ReagentSingleton.Instance.GetReagentToGas(Reagent.Key), Reagent.Value); } } }
/// <summary> /// This is called whenever blood is pumped through the circulatory system by a heartbeat. /// Can happen multiple times if there's multiple hearts. Pushes out old blood and brings /// in new blood, up to the part's capacity. /// </summary> /// <param name="bloodIn">Incoming blood</param> /// <returns>Whatever is left over from bloodIn</returns> public void BloodPumpedEvent(ReagentMix bloodIn) { //Maybe have damage from high/low blood levels and high blood pressure BloodContainer.CurrentReagentMix.TransferTo(HealthMaster.CirculatorySystem.UsedBloodPool, (BloodContainer.CurrentReagentMix.Total + bloodIn.Total) - BloodThroughput); bloodIn.TransferTo(BloodContainer.CurrentReagentMix, bloodIn.Total); BloodContainer.OnReagentMixChanged?.Invoke(); BloodContainer.ReagentsChanged(); BloodWasPumped(); }
public void RemovalTest( int capacity, ReagentMix initial, int amountToMove, ReagentMix final) { var container = GetContainer(capacity, initial); container.TakeReagents(amountToMove); AssertContainerContentsEqualTo(container, final); }
public void AdditionTest( int capacity, ReagentMix initial, ReagentMix toAdd, ReagentMix final) { var container = GetContainer(capacity, initial); container.Add(toAdd); AssertContainerContentsEqualTo(container, final); }
/// <summary> /// Server only: /// Picks best matching matrix at provided coords and releases reagents to that tile. /// <inheritdoc cref="MetaDataLayer.ReagentReact"/> /// </summary> public static void ReagentReact(ReagentMix reagents, Vector3Int worldPos) { if (!CustomNetworkManager.IsServer) { return; } var matrixInfo = AtPoint(worldPos, true); Vector3Int localPos = WorldToLocalInt(worldPos, matrixInfo); matrixInfo.MetaDataLayer.ReagentReact(reagents, worldPos, localPos); }
private static ReagentContainer GetContainer(int maxCapacity, ReagentMix contents) { GameObject obj = new GameObject(); obj.AddComponent <ReagentContainer>(); ReagentContainer container = obj.GetComponent <ReagentContainer>(); container.ReactionSet = new ReactionSet(); container.maxCapacity = maxCapacity; container.Add(contents); return(container); }
/// <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> /// Performs the action of breathing, expelling waste products from the used blood pool and refreshing /// the desired blood reagent (ie oxygen) /// </summary> /// <param name="node">The gas node at this lung's position</param> /// <returns>True if gas was exchanged</returns> public bool TryBreathing(IGasMixContainer node, float efficiency) { //Base effeciency is a little strong on the lungs //efficiency = (1 + efficiency) / 2; //Breathing is not timebased, but tick based, it will be slow when the blood has all the oxygen it needs //and will speed up if more oxygen is needed currentBreatheCooldown--; if (currentBreatheCooldown > 0) { return(false); } if (RelatedPart.HealthMaster.CirculatorySystem.BloodPool[RelatedPart.bloodType] == 0) { return(false); //No point breathing if we dont have blood. } // Try to get internal breathing if possible, otherwise get from the surroundings IGasMixContainer container = RelatedPart.HealthMaster.RespiratorySystem.GetInternalGasMix(); var gasMixSink = node.GasMix; // Where to dump lung exhaust if (container == null) { // Could be in a container that has an internal gas mix, else use the tile's gas mix. var parentContainer = RelatedPart.HealthMaster.ObjectBehaviour.parentContainer; if (parentContainer != null && parentContainer.TryGetComponent <GasContainer>(out var gasContainer)) { container = gasContainer; gasMixSink = container.GasMix; } else { container = node; } } if (efficiency > 1) { efficiency = 1; } ReagentMix AvailableBlood = RelatedPart.HealthMaster.CirculatorySystem.BloodPool.Take( (RelatedPart.HealthMaster.CirculatorySystem.BloodPool.Total * efficiency) / 2f); bool tryExhale = BreatheOut(gasMixSink, AvailableBlood); bool tryInhale = BreatheIn(container.GasMix, AvailableBlood, efficiency); RelatedPart.HealthMaster.CirculatorySystem.BloodPool.Add(AvailableBlood); return(tryExhale || tryInhale); }
/// <summary> /// Takes reagents from blood and puts them into a GasMix as gases /// </summary> public void GasExchangeFromBlood(GasMix atmos, ReagentMix blood, ReagentMix toProcess) { foreach (var reagent in toProcess.reagents.m_dict) { blood.Remove(reagent.Key, float.MaxValue); if (canBreathAnywhere || Gas.ReagentToGas.TryGetValue(reagent.Key, out var gas) == false) { continue; } atmos.AddGas(gas, reagent.Value); } }
public virtual void Eat(PlayerScript eater, PlayerScript feeder) { //TODO: Reimplement metabolism. AudioSourceParameters eatSoundParameters = new AudioSourceParameters(pitch: RandomPitch); SoundManager.PlayNetworkedAtPos(sound, eater.WorldPos, eatSoundParameters, sourceObj: eater.gameObject); var Stomachs = eater.playerHealth.GetStomachs(); if (Stomachs.Count == 0) { //No stomachs?! return; } ReagentMix incomingFood = new ReagentMix(); FoodContents.CurrentReagentMix.TransferTo(incomingFood, FoodContents.CurrentReagentMix.Total); incomingFood.Divide(Stomachs.Count); foreach (var Stomach in Stomachs) { Stomach.StomachContents.Add(incomingFood.Clone()); } var feederSlot = feeder.DynamicItemStorage.GetActiveHandSlot(); //If food has a stack component, decrease amount by one instead of deleting the entire stack. if (stackable != null) { stackable.ServerConsume(1); } else { Inventory.ServerDespawn(gameObject); } if (leavings != null) { var leavingsInstance = Spawn.ServerPrefab(leavings).GameObject; var pickupable = leavingsInstance.GetComponent <Pickupable>(); bool added = Inventory.ServerAdd(pickupable, feederSlot); if (!added) { //If stackable has leavings and they couldn't go in the same slot, they should be dropped pickupable.CustomNetTransform.SetPosition(feeder.WorldPos); } } }
public float GetSpareGasCapacityForeign(ReagentMix reagentMix, Reagent reagent = null) { float toReturn = 0; foreach (var reagen in reagentMix) { var kindOfBlood = reagen.Key as BloodType; if (kindOfBlood != null && kindOfBlood != this) { toReturn += kindOfBlood.GetSpareGasCapacity(reagentMix, reagent); } } return(toReturn); }