コード例 #1
0
    /// <summary>
    ///   Absorbs compounds from this cloud
    /// </summary>
    public void AbsorbCompounds(int localX, int localY, CompoundBag storage,
                                Dictionary <Compound, float> totals, float delta, float rate)
    {
        var fractionToTake = 1.0f - (float)Math.Pow(0.5f, delta / Constants.CLOUD_ABSORPTION_HALF_LIFE);

        for (int i = 0; i < Constants.CLOUDS_IN_ONE; i++)
        {
            if (Compounds[i] == null)
            {
                break;
            }

            // Skip if compound is non-useful
            if (!storage.IsUseful(Compounds[i]))
            {
                continue;
            }

            // Overestimate of how much compounds we get
            float generousAmount = HackyAddress(Density[localX, localY], i) *
                                   Constants.SKIP_TRYING_TO_ABSORB_RATIO;

            // Skip if there isn't enough to absorb
            if (generousAmount < MathUtils.EPSILON)
            {
                continue;
            }

            float freeSpace = storage.Capacity - storage.GetCompoundAmount(Compounds[i]);

            float multiplier = 1.0f * rate;

            if (freeSpace < generousAmount)
            {
                // Allow partial absorption to allow cells to take from high density clouds
                multiplier = freeSpace / generousAmount;
            }

            float taken = TakeCompound(Compounds[i], localX, localY, fractionToTake * multiplier) *
                          Constants.ABSORPTION_RATIO;

            storage.AddCompound(Compounds[i], taken);

            // Keep track of total compounds absorbed for the cell
            if (!totals.ContainsKey(Compounds[i]))
            {
                totals.Add(Compounds[i], taken);
            }
            else
            {
                totals[Compounds[i]] += taken;
            }
        }
    }
コード例 #2
0
    /// <summary>
    ///   Gives organelles more compounds to grow
    /// </summary>
    public void GrowOrganelle(CompoundBag compounds)
    {
        float totalTaken = 0;
        var   keys       = new List <string>(compoundsLeft.Keys);

        foreach (var key in keys)
        {
            var amountNeeded = compoundsLeft[key];

            if (amountNeeded <= 0.0f)
            {
                continue;
            }

            // Take compounds if the cell has what we need
            // ORGANELLE_GROW_STORAGE_MUST_HAVE_AT_LEAST controls how
            // much of a certain compound must exist before we take
            // some
            var amountAvailable = compounds.GetCompoundAmount(key)
                                  - Constants.ORGANELLE_GROW_STORAGE_MUST_HAVE_AT_LEAST;

            if (amountAvailable <= 0.0f)
            {
                continue;
            }

            // We can take some
            var amountToTake = Mathf.Min(amountNeeded, amountAvailable);

            var amount = compounds.TakeCompound(key, amountToTake);
            var left   = amountNeeded - amount;

            if (left < 0.0001)
            {
                left = 0;
            }

            compoundsLeft[key] = left;

            totalTaken += amount;
        }

        if (totalTaken > 0)
        {
            growthValueDirty = true;

            ApplyScale();
        }
    }
コード例 #3
0
    /// <summary>
    ///   Absorbs compounds from this cloud
    /// </summary>
    public void AbsorbCompounds(int localX, int localY, CompoundBag storage,
                                Dictionary <string, float> totals, float delta)
    {
        var fractionToTake = 1.0f - (float)Math.Pow(0.5f, delta / Constants.CLOUD_ABSORPTION_HALF_LIFE);

        foreach (var slot in slots)
        {
            // Overestimate of how much compounds we get
            float generousAmount = slot.Density[localX, localY] *
                                   Constants.SKIP_TRYING_TO_ABSORB_RATIO;

            // Skip if there isn't enough to absorb
            if (generousAmount < MathUtils.EPSILON)
            {
                continue;
            }

            var compound = slot.Compound.InternalName;

            float freeSpace = storage.Capacity - storage.GetCompoundAmount(compound);

            float multiplier = 1.0f;

            if (freeSpace < generousAmount)
            {
                // Allow partial absorption to allow cells to take from high density clouds
                multiplier = freeSpace / generousAmount;
            }

            float taken = slot.TakeCompound(localX, localY, fractionToTake * multiplier) *
                          Constants.ABSORPTION_RATIO;

            storage.AddCompound(compound, taken);

            // Keep track of total compounds absorbed for the cell
            if (!totals.ContainsKey(compound))
            {
                totals.Add(compound, taken);
            }
            else
            {
                totals[compound] += taken;
            }
        }
    }
コード例 #4
0
    private void RunProcess(float delta, BioProcess processData, CompoundBag bag, TweakedProcess process,
                            SingleProcessStatistics currentProcessStatistics, float inverseDelta)
    {
        // Can your cell do the process
        bool canDoProcess = true;

        // Loop through to make sure you can follow through with your
        // whole process so nothing gets wasted as that would be
        // frustrating.
        float environmentModifier = 1.0f;

        // First check the environmental compounds so that we can build the right environment modifier for accurate
        // check of normal compound input amounts
        foreach (var entry in processData.Inputs)
        {
            // Set used compounds to be useful, we dont want to purge
            // those
            bag.SetUseful(entry.Key);

            if (!entry.Key.IsEnvironmental)
            {
                continue;
            }

            var dissolved = GetDissolved(entry.Key);

            // currentProcessStatistics?.AddInputAmount(entry.Key, entry.Value * inverseDelta);
            currentProcessStatistics?.AddInputAmount(entry.Key, dissolved);

            // do environmental modifier here, and save it for later
            environmentModifier *= dissolved / entry.Value;

            if (environmentModifier <= MathUtils.EPSILON)
            {
                currentProcessStatistics?.AddLimitingFactor(entry.Key);
            }
        }

        if (environmentModifier <= MathUtils.EPSILON)
        {
            canDoProcess = false;
        }

        foreach (var entry in processData.Inputs)
        {
            if (entry.Key.IsEnvironmental)
            {
                continue;
            }

            var inputRemoved = entry.Value * process.Rate * delta;

            currentProcessStatistics?.AddInputAmount(entry.Key, inputRemoved * inverseDelta);

            // currentProcessStatistics?.AddInputAmount(entry.Key, 0);

            // If not enough compound we can't do the process
            if (bag.GetCompoundAmount(entry.Key) < inputRemoved)
            {
                canDoProcess = false;
                currentProcessStatistics?.AddLimitingFactor(entry.Key);
            }
        }

        // Output
        // This is now always looped (even when we can't do the process)
        // because the is useful part is needs to be always be done
        foreach (var entry in processData.Outputs)
        {
            // For now lets assume compounds we produce are also
            // useful
            bag.SetUseful(entry.Key);

            // Apply the general modifiers and
            // apply the environmental modifier
            var outputAdded = entry.Value * process.Rate * delta * environmentModifier;

            currentProcessStatistics?.AddOutputAmount(entry.Key, outputAdded * inverseDelta);

            // currentProcessStatistics?.AddOutputAmount(entry.Key, 0);

            // If no space we can't do the process, and if environmental
            // right now this isn't released anywhere
            if (entry.Key.IsEnvironmental)
            {
                continue;
            }

            if (bag.GetCompoundAmount(entry.Key) + outputAdded > bag.Capacity)
            {
                canDoProcess = false;
                currentProcessStatistics?.AddCapacityProblem(entry.Key);
            }
        }

        // Only carry out this process if you have all the required
        // ingredients and enough space for the outputs
        if (!canDoProcess)
        {
            return;
        }

        if (currentProcessStatistics != null)
        {
            currentProcessStatistics.CurrentSpeed = process.Rate * environmentModifier;
        }

        // Consume inputs
        foreach (var entry in processData.Inputs)
        {
            if (entry.Key.IsEnvironmental)
            {
                continue;
            }

            var inputRemoved = entry.Value * process.Rate * delta *
                               environmentModifier;

            currentProcessStatistics?.AddInputAmount(entry.Key, inputRemoved * inverseDelta);

            // This should always succeed (due to the earlier check) so
            // it is always assumed here that the process succeeded
            bag.TakeCompound(entry.Key, inputRemoved);
        }

        // Add outputs
        foreach (var entry in processData.Outputs)
        {
            if (entry.Key.IsEnvironmental)
            {
                continue;
            }

            var outputGenerated = entry.Value * process.Rate * delta *
                                  environmentModifier;

            currentProcessStatistics?.AddOutputAmount(entry.Key, outputGenerated * inverseDelta);

            bag.AddCompound(entry.Key, outputGenerated);
        }
    }
コード例 #5
0
ファイル: ProcessSystem.cs プロジェクト: Shupsta/Thrive
    private void RunProcess(float delta, BioProcess processData, CompoundBag bag, TweakedProcess process,
                            SingleProcessStatistics currentProcessStatistics, float inverseDelta)
    {
        // Can your cell do the process
        bool canDoProcess = true;

        float environmentModifier = 1.0f;

        // This modifies the process overall speed to allow really fast processes to run, for example if there are
        // a ton of one organelle it might consume 100 glucose per go, which might be unlikely for the cell to have
        // so if there is *some* but not enough space for results (and also inputs) this can run the process as
        // fraction of the speed to allow the cell to still function well
        float spaceConstraintModifier = 1.0f;

        // First check the environmental compounds so that we can build the right environment modifier for accurate
        // check of normal compound input amounts
        foreach (var entry in processData.Inputs)
        {
            // Set used compounds to be useful, we dont want to purge those
            bag.SetUseful(entry.Key);

            if (!entry.Key.IsEnvironmental)
            {
                continue;
            }

            var dissolved = GetDissolved(entry.Key);

            // currentProcessStatistics?.AddInputAmount(entry.Key, entry.Value * inverseDelta);
            currentProcessStatistics?.AddInputAmount(entry.Key, dissolved);

            // do environmental modifier here, and save it for later
            environmentModifier *= dissolved / entry.Value;

            if (environmentModifier <= MathUtils.EPSILON)
            {
                currentProcessStatistics?.AddLimitingFactor(entry.Key);
            }
        }

        if (environmentModifier <= MathUtils.EPSILON)
        {
            canDoProcess = false;
        }

        // Compute spaceConstraintModifier before updating the final use and input amounts
        foreach (var entry in processData.Inputs)
        {
            if (entry.Key.IsEnvironmental)
            {
                continue;
            }

            var inputRemoved = entry.Value * process.Rate * environmentModifier;

            // currentProcessStatistics?.AddInputAmount(entry.Key, 0);
            // We don't multiply by delta here because we report the per-second values anyway. In the actual process
            // output numbers (computed after testing the speed), we need to multiply by inverse delta
            currentProcessStatistics?.AddInputAmount(entry.Key, inputRemoved);

            inputRemoved = inputRemoved * delta * spaceConstraintModifier;

            // If not enough we can't run the process unless we can lower spaceConstraintModifier enough
            var availableAmount = bag.GetCompoundAmount(entry.Key);
            if (availableAmount < inputRemoved)
            {
                bool canRun = false;

                if (availableAmount > MathUtils.EPSILON)
                {
                    var neededModifier = availableAmount / inputRemoved;

                    if (neededModifier > Constants.MINIMUM_RUNNABLE_PROCESS_FRACTION)
                    {
                        spaceConstraintModifier = neededModifier;
                        canRun = true;

                        // Due to rounding errors there can be very small disparity here between the amount available
                        // and what we will take with the modifiers. See the comment in outputs for more details
                    }
                }

                if (!canRun)
                {
                    canDoProcess = false;
                    currentProcessStatistics?.AddLimitingFactor(entry.Key);
                }
            }
        }

        foreach (var entry in processData.Outputs)
        {
            // For now lets assume compounds we produce are also useful
            bag.SetUseful(entry.Key);

            var outputAdded = entry.Value * process.Rate * environmentModifier;

            // currentProcessStatistics?.AddOutputAmount(entry.Key, 0);
            currentProcessStatistics?.AddOutputAmount(entry.Key, outputAdded);

            outputAdded = outputAdded * delta * spaceConstraintModifier;

            // if environmental right now this isn't released anywhere
            if (entry.Key.IsEnvironmental)
            {
                continue;
            }

            // If no space we can't do the process, if we can't adjust the space constraint modifier enough
            var remainingSpace = bag.Capacity - bag.GetCompoundAmount(entry.Key);
            if (outputAdded > remainingSpace)
            {
                bool canRun = false;

                if (remainingSpace > MathUtils.EPSILON)
                {
                    var neededModifier = remainingSpace / outputAdded;

                    if (neededModifier > Constants.MINIMUM_RUNNABLE_PROCESS_FRACTION)
                    {
                        spaceConstraintModifier = neededModifier;
                        canRun = true;
                    }

                    // With all of the modifiers we can lose a tiny bit of compound that won't fit due to rounding
                    // errors, but we ignore that here
                }

                if (!canRun)
                {
                    canDoProcess = false;
                    currentProcessStatistics?.AddCapacityProblem(entry.Key);
                }
            }
        }

        // Only carry out this process if you have all the required ingredients and enough space for the outputs
        if (!canDoProcess)
        {
            if (currentProcessStatistics != null)
            {
                currentProcessStatistics.CurrentSpeed = 0;
            }
            return;
        }

        float totalModifier = process.Rate * delta * environmentModifier * spaceConstraintModifier;

        if (currentProcessStatistics != null)
        {
            currentProcessStatistics.CurrentSpeed = process.Rate * environmentModifier * spaceConstraintModifier;
        }

        // Consume inputs
        foreach (var entry in processData.Inputs)
        {
            if (entry.Key.IsEnvironmental)
            {
                continue;
            }

            var inputRemoved = entry.Value * totalModifier;

            currentProcessStatistics?.AddInputAmount(entry.Key, inputRemoved * inverseDelta);

            // This should always succeed (due to the earlier check) so it is always assumed here that this succeeded
            bag.TakeCompound(entry.Key, inputRemoved);
        }

        // Add outputs
        foreach (var entry in processData.Outputs)
        {
            if (entry.Key.IsEnvironmental)
            {
                continue;
            }

            var outputGenerated = entry.Value * totalModifier;

            currentProcessStatistics?.AddOutputAmount(entry.Key, outputGenerated * inverseDelta);

            bag.AddCompound(entry.Key, outputGenerated);
        }
    }
コード例 #6
0
ファイル: Microbe.Interior.cs プロジェクト: Shupsta/Thrive
    /// <summary>
    ///   Tries to fire a toxin if possible
    /// </summary>
    public void EmitToxin(Compound agentType = null)
    {
        if (AgentEmissionCooldown > 0)
        {
            return;
        }

        // Only shoot if you have an agent vacuole.
        if (AgentVacuoleCount < 1)
        {
            return;
        }

        agentType ??= SimulationParameters.Instance.GetCompound("oxytoxy");

        float amountAvailable = Compounds.GetCompoundAmount(agentType);

        // Emit as much as you have, but don't start the cooldown if that's zero
        float amountEmitted = Math.Min(amountAvailable, Constants.MAXIMUM_AGENT_EMISSION_AMOUNT);

        if (amountEmitted < Constants.MINIMUM_AGENT_EMISSION_AMOUNT)
        {
            return;
        }

        Compounds.TakeCompound(agentType, amountEmitted);

        // The cooldown time is inversely proportional to the amount of agent vacuoles.
        AgentEmissionCooldown = Constants.AGENT_EMISSION_COOLDOWN / AgentVacuoleCount;

        float ejectionDistance = Membrane.EncompassingCircleRadius +
                                 Constants.AGENT_EMISSION_DISTANCE_OFFSET;

        if (Species.IsBacteria)
        {
            ejectionDistance *= 0.5f;
        }

        var props = new AgentProperties();

        props.Compound = agentType;
        props.Species  = Species;

        // Find the direction the microbe is facing
        var direction = (LookAtPoint - Translation).Normalized();

        var position = Translation + (direction * ejectionDistance);

        var agent = SpawnHelpers.SpawnAgent(props, amountEmitted, Constants.EMITTED_AGENT_LIFETIME,
                                            position, direction, GetStageAsParent(),
                                            SpawnHelpers.LoadAgentScene(), this);

        ModLoader.ModInterface.TriggerOnToxinEmitted(agent);

        if (amountEmitted < Constants.MAXIMUM_AGENT_EMISSION_AMOUNT / 2)
        {
            PlaySoundEffect("res://assets/sounds/soundeffects/microbe-release-toxin-low.ogg");
        }
        else
        {
            PlaySoundEffect("res://assets/sounds/soundeffects/microbe-release-toxin.ogg");
        }
    }