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);
        }
Esempio n. 3
0
    /// <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);
    }
Esempio n. 4
0
        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);
        }
Esempio n. 5
0
        /// <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");
     }
 }
Esempio n. 7
0
    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");
         }
     }
 }
Esempio n. 9
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);
                }
            }
        }
Esempio n. 10
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);
        }
    }
    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);
        }
Esempio n. 13
0
 public float GetGasCapacity(ReagentMix reagentMix, Reagent reagent = null)
 {
     if (reagent == CirculatedReagent || reagent == null)
     {
         return(reagentMix[this] * BloodCapacityOf);
     }
     return(reagentMix[this] * BloodGasCapability);
 }
Esempio n. 14
0
 public float GetGasCapacity(ReagentMix reagentMix, Reagent reagent)
 {
     if (reagent == CirculatedReagent || reagent == null)
     {
         return(GetNormalGasCapacity(reagentMix));
     }
     return(GetSpecialGasCapacity(reagentMix));
 }
Esempio n. 15
0
 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);
        }
Esempio n. 17
0
    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);
    }
Esempio n. 18
0
        /// <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);
    }
Esempio n. 20
0
 /// <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);
         }
     }
 }
Esempio n. 21
0
        /// <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);
        }
Esempio n. 24
0
    /// <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);
    }
Esempio n. 25
0
        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);
        }
Esempio n. 26
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
        }
Esempio n. 27
0
        /// <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);
        }
Esempio n. 28
0
        /// <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);
            }
        }
Esempio n. 29
0
        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);
                }
            }
        }
Esempio n. 30
0
        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);
        }