public void Inhale(float frameTime, GasMixture from)
        {
            var ratio = Atmospherics.BreathPercentage * frameTime;


            Transfer(from, Air, ratio);
            ToBloodstream(Air);
        }
        public override void ExposeData(ObjectSerializer serializer)
        {
            base.ExposeData(serializer);

            Air = new GasMixture(6);

            serializer.DataField(ref _initialMaxVolume, "maxVolume", ReagentUnit.New(250));
        }
Beispiel #3
0
        public override void ExposeData(ObjectSerializer serializer)
        {
            base.ExposeData(serializer);

            Air = new GasMixture();

            serializer.DataField(this, x => x.Air, "air", new GasMixture());
        }
        public static bool IsMixtureOxygenated(GasMixture gas, float partial)
        {
            if (gas.O2Partial >= partial)
            {
                return(true);
            }

            return(false);
        }
        public static bool IsMixtureCo2Toxic(GasMixture gas)
        {
            if (gas.Co2Partial >= 5f)//conditions for hypercapnia
            {
                return(true);
            }

            return(true);
        }
 /// <summary>
 /// Calculates the molar density of a given gas mixture in g/mol.
 /// </summary>
 /// <param name="mix">GasMixture to have its desnity calculated.</param>
 /// <returns>Gas density (g/mol)</returns>
 public static float MolarGasDensity(GasMixture mix)
 {
     return((mix.Oxygen.Quantity / mix.TotalMolesGassesAndLiquids * 31.9988f) +
            (mix.Nitrogen.Quantity / mix.TotalMolesGassesAndLiquids * 28.0134f) +
            (mix.CarbonDioxide.Quantity / mix.TotalMolesGassesAndLiquids * 44.0095f) +
            (mix.Volatiles.Quantity / mix.TotalMolesGassesAndLiquids * 2.01588f) +
            (mix.Pollutant.Quantity / mix.TotalMolesGassesAndLiquids * 70.906f) +
            (mix.Water.Quantity / mix.TotalMolesGassesAndLiquids * 18.0153f));
 }
Beispiel #7
0
        public void Transfer(BloodstreamComponent @from, GasMixture to, Gas gas, float pressure)
        {
            var transfer     = new GasMixture();
            var molesInBlood = @from.Air.GetMoles(gas);

            transfer.SetMoles(gas, molesInBlood);
            transfer.ReleaseGasTo(to, pressure);

            @from.Air.Merge(transfer);
        }
Beispiel #8
0
        private void OnFilterUpdated(EntityUid uid, GasFilterComponent filter, AtmosDeviceUpdateEvent args)
        {
            var appearance = EntityManager.GetComponentOrNull <AppearanceComponent>(filter.Owner);

            if (!filter.Enabled ||
                !EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) ||
                !EntityManager.TryGetComponent(uid, out AtmosDeviceComponent? device) ||
                !nodeContainer.TryGetNode(filter.InletName, out PipeNode? inletNode) ||
                !nodeContainer.TryGetNode(filter.FilterName, out PipeNode? filterNode) ||
                !nodeContainer.TryGetNode(filter.OutletName, out PipeNode? outletNode) ||
                outletNode.Air.Pressure >= Atmospherics.MaxOutputPressure) // No need to transfer if target is full.
            {
                appearance?.SetData(FilterVisuals.Enabled, false);
                _ambientSoundSystem.SetAmbience(filter.Owner, false);
                return;
            }

            // We multiply the transfer rate in L/s by the seconds passed since the last process to get the liters.
            var transferRatio = (float)(filter.TransferRate * (_gameTiming.CurTime - device.LastProcess).TotalSeconds) / inletNode.Air.Volume;

            if (transferRatio <= 0)
            {
                appearance?.SetData(FilterVisuals.Enabled, false);
                _ambientSoundSystem.SetAmbience(filter.Owner, false);
                return;
            }

            var removed = inletNode.Air.RemoveRatio(transferRatio);

            if (filter.FilteredGas.HasValue)
            {
                appearance?.SetData(FilterVisuals.Enabled, true);

                var filteredOut = new GasMixture()
                {
                    Temperature = removed.Temperature
                };

                filteredOut.SetMoles(filter.FilteredGas.Value, removed.GetMoles(filter.FilteredGas.Value));
                removed.SetMoles(filter.FilteredGas.Value, 0f);

                var target = filterNode.Air.Pressure < Atmospherics.MaxOutputPressure ? filterNode : inletNode;
                _atmosphereSystem.Merge(target.Air, filteredOut);
                if (filteredOut.Pressure != 0f)
                {
                    _ambientSoundSystem.SetAmbience(filter.Owner, true);
                }
                else
                {
                    _ambientSoundSystem.SetAmbience(filter.Owner, false);
                }
            }

            _atmosphereSystem.Merge(outletNode.Air, removed);
        }
Beispiel #9
0
    public float pressure    = 0;       // in kPa

    void Start()
    {
        // Get surrounding tiles, because we will need to update them
        surroundedTiles = new List <Tile>();
        surroundedTiles.Add(GetSurroundedTile(transform.forward));
        surroundedTiles.Add(GetSurroundedTile(-transform.right));
        surroundedTiles.Add(GetSurroundedTile(-transform.forward));
        surroundedTiles.Add(GetSurroundedTile(transform.right));

        gasMixture = new GasMixture();
    }
        public override void ExposeData(ObjectSerializer serializer)
        {
            base.ExposeData(serializer);

            Air = new GasMixture(6)
            {
                Temperature = Atmospherics.NormalBodyTemperature
            };

            serializer.DataField(ref _initialMaxVolume, "maxVolume", ReagentUnit.New(250));
        }
        private void OnFilterUpdated(EntityUid uid, GasFilterComponent filter, AtmosDeviceUpdateEvent args)
        {
            if (!filter.Enabled)
            {
                return;
            }

            if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
            {
                return;
            }

            if (!ComponentManager.TryGetComponent(uid, out AtmosDeviceComponent? device))
            {
                return;
            }

            if (!nodeContainer.TryGetNode(filter.InletName, out PipeNode? inletNode) ||
                !nodeContainer.TryGetNode(filter.FilterName, out PipeNode? filterNode) ||
                !nodeContainer.TryGetNode(filter.OutletName, out PipeNode? outletNode))
            {
                return;
            }

            if (outletNode.Air.Pressure >= Atmospherics.MaxOutputPressure)
            {
                return; // No need to transfer if target is full.
            }
            // We multiply the transfer rate in L/s by the seconds passed since the last process to get the liters.
            var transferRatio = (float)(filter.TransferRate * (_gameTiming.CurTime - device.LastProcess).TotalSeconds) / inletNode.Air.Volume;

            if (transferRatio <= 0)
            {
                return;
            }

            var removed = inletNode.Air.RemoveRatio(transferRatio);

            if (filter.FilteredGas.HasValue)
            {
                var filteredOut = new GasMixture()
                {
                    Temperature = removed.Temperature
                };

                filteredOut.SetMoles(filter.FilteredGas.Value, removed.GetMoles(filter.FilteredGas.Value));
                removed.SetMoles(filter.FilteredGas.Value, 0f);

                var target = filterNode.Air.Pressure < Atmospherics.MaxOutputPressure ? filterNode : inletNode;
                target.AssumeAir(filteredOut);
            }

            outletNode.AssumeAir(removed);
        }
Beispiel #12
0
        public ReactionResult React(GasMixture mixture, IGasMixtureHolder holder, GridTileLookupSystem gridLookup)
        {
            var result = ReactionResult.NoReaction;

            foreach (var effect in _effects)
            {
                result |= effect.React(mixture, holder, gridLookup);
            }

            return(result);
        }
Beispiel #13
0
        public ReactionResult React(GasMixture mixture, IGasMixtureHolder holder)
        {
            var result = ReactionResult.NoReaction;

            foreach (var effect in _effects)
            {
                result |= effect.React(mixture, holder);
            }

            return(result);
        }
Beispiel #14
0
 public void Update(GasMixture air, float frameDelta, AtmosphereSystem atmosphereSystem)
 {
     // TODO: I'm coming for you next, TemperatureComponent... Fear me for I am death, destroyer of shitcode.
     if (_temperatureComponent != null)
     {
         var temperatureDelta = air.Temperature - _temperatureComponent.CurrentTemperature;
         var tileHeatCapacity = atmosphereSystem.GetHeatCapacity(air);
         var heat             = temperatureDelta * (tileHeatCapacity * _temperatureComponent.HeatCapacity / (tileHeatCapacity + _temperatureComponent.HeatCapacity));
         _temperatureComponent.ReceiveHeat(heat);
         _temperatureComponent.Update();
     }
 }
Beispiel #15
0
        public void ToBloodstream(GasMixture mixture)
        {
            if (!Owner.TryGetComponent(out BloodstreamComponent bloodstream))
            {
                return;
            }

            var to = bloodstream.Air;

            to.Merge(mixture);
            mixture.Clear();
        }
        public override void ExposeData(ObjectSerializer serializer)
        {
            base.ExposeData(serializer);

            GasMixture = new GasMixture();

            serializer.DataReadWriteFunction(
                "volume",
                0f,
                vol => GasMixture.Volume = vol,
                () => GasMixture.Volume);
        }
    public ReactionResult React(GasMixture mixture, IGasMixtureHolder?holder, AtmosphereSystem atmosphereSystem)
    {
        var initialMiasma = mixture.GetMoles(Gas.Miasma);
        var initialFrezon = mixture.GetMoles(Gas.Frezon);

        var convert = Math.Min(Math.Min(initialFrezon, initialMiasma), Atmospherics.MiasmicSubsumationMaxConversionRate);

        mixture.AdjustMoles(Gas.Miasma, convert);
        mixture.AdjustMoles(Gas.Frezon, -convert);

        return(ReactionResult.Reacting);
    }
Beispiel #18
0
    public ReactionResult React(GasMixture mixture, IGasMixtureHolder?holder, AtmosphereSystem atmosphereSystem)
    {
        var oldHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture);
        var temperature     = mixture.Temperature;

        var energyModifier = 1f;
        var scale          = (temperature - Atmospherics.FrezonCoolLowerTemperature) /
                             (Atmospherics.FrezonCoolMidTemperature - Atmospherics.FrezonCoolLowerTemperature);

        if (scale > 1f)
        {
            // Scale energy but not frezon usage if we're in a very, very hot place
            energyModifier = Math.Min(scale, Atmospherics.FrezonCoolMaximumEnergyModifier);
            scale          = 1f;
        }

        if (scale <= 0)
        {
            return(ReactionResult.NoReaction);
        }

        var initialNit    = mixture.GetMoles(Gas.Nitrogen);
        var initialFrezon = mixture.GetMoles(Gas.Frezon);

        var burnRate = initialFrezon * scale / Atmospherics.FrezonCoolRateModifier;

        var energyReleased = 0f;

        if (burnRate > Atmospherics.MinimumHeatCapacity)
        {
            var nitAmt    = Math.Min(burnRate * Atmospherics.FrezonNitrogenCoolRatio, initialNit);
            var frezonAmt = Math.Min(burnRate, initialFrezon);
            mixture.AdjustMoles(Gas.Nitrogen, -nitAmt);
            mixture.AdjustMoles(Gas.Frezon, -frezonAmt);
            mixture.AdjustMoles(Gas.NitrousOxide, nitAmt + frezonAmt);
            energyReleased = burnRate * Atmospherics.FrezonCoolEnergyReleased * energyModifier;
        }

        if (energyReleased >= 0f)
        {
            return(ReactionResult.NoReaction);
        }

        var newHeatCapacity = atmosphereSystem.GetHeatCapacity(mixture);

        if (newHeatCapacity > Atmospherics.MinimumHeatCapacity)
        {
            mixture.Temperature = (temperature * oldHeatCapacity + energyReleased) / newHeatCapacity;
        }

        return(ReactionResult.Reacting);
    }
Beispiel #19
0
        public void PumpToxins(GasMixture into, float pressure)
        {
            if (!Owner.TryGetComponent(out MetabolismComponent metabolism))
            {
                Air.PumpGasTo(into, pressure);
                return;
            }

            var toxins = metabolism.Clean(this);

            toxins.PumpGasTo(into, pressure);
            Air.Merge(toxins);
        }
        public override void ExposeData(ObjectSerializer serializer)
        {
            base.ExposeData(serializer);

            Air = new GasMixture();

            serializer.DataReadWriteFunction(
                "volume",
                6,
                vol => Air.Volume = vol,
                () => Air.Volume);
            serializer.DataField(this, l => l.Pressure, "pressure", 100);
        }
Beispiel #21
0
        private void ExcitedGroupSelfBreakdown(GridAtmosphereComponent gridAtmosphere, ExcitedGroup excitedGroup)
        {
            DebugTools.Assert(!excitedGroup.Disposed, "Excited group is disposed!");
            DebugTools.Assert(gridAtmosphere.ExcitedGroups.Contains(excitedGroup), "Grid Atmosphere does not contain Excited Group!");
            var combined = new GasMixture(Atmospherics.CellVolume);

            var tileSize = excitedGroup.Tiles.Count;

            if (excitedGroup.Disposed)
            {
                return;
            }

            if (tileSize == 0)
            {
                ExcitedGroupDispose(gridAtmosphere, excitedGroup);
                return;
            }

            foreach (var tile in excitedGroup.Tiles)
            {
                if (tile?.Air == null)
                {
                    continue;
                }

                Merge(combined, tile.Air);

                if (!ExcitedGroupsSpaceIsAllConsuming || !tile.Air.Immutable)
                {
                    continue;
                }

                combined.Clear();
                break;
            }

            combined.Multiply(1 / (float)tileSize);

            foreach (var tile in excitedGroup.Tiles)
            {
                if (tile?.Air == null)
                {
                    continue;
                }
                tile.Air.CopyFromMutable(combined);
                InvalidateVisuals(tile.GridIndex, tile.GridIndices);
            }

            excitedGroup.BreakdownCooldown = 0;
        }
Beispiel #22
0
    private void UpdateTileTemperature(TemperatureArtifactComponent component, GasMixture environment)
    {
        var dif    = component.TargetTemperature - environment.Temperature;
        var absDif = Math.Abs(dif);

        if (absDif < component.MaxTemperatureDifference)
        {
            return;
        }

        var step = Math.Min(absDif, component.SpawnTemperature);

        environment.Temperature += dif > 0 ? step : -step;
    }
        public static bool IsMixtureToxic(GasMixture gas)
        {
            if (IsMixtureCo2Toxic(gas))//conditions for hypercapnia
            {
                return(true);
            }

            if (!IsMixtureOxygenated(gas))
            {
                return(true);
            }

            return(false);
        }
Beispiel #24
0
    private void RefillGasTank(EntityUid tank, Gas gasType, GasTankComponent?tankComponent)
    {
        if (!Resolve(tank, ref tankComponent))
        {
            return;
        }

        var mixSize = tankComponent.Air.Volume;
        var newMix  = new GasMixture(mixSize);

        newMix.SetMoles(gasType, (1000.0f * mixSize) / (Atmospherics.R * Atmospherics.T20C)); // Fill the tank to 1000KPA.
        newMix.Temperature = Atmospherics.T20C;
        tankComponent.Air  = newMix;
    }
Beispiel #25
0
        /// <summary>
        ///     Divides a source gas mixture into several recipient mixtures, scaled by their relative volumes. Does not
        ///     modify the source gas mixture. Used for pipe network splitting. Note that the total destination volume
        ///     may be larger or smaller than the source mixture.
        /// </summary>
        public void DivideInto(GasMixture source, List <GasMixture> receivers)
        {
            var totalVolume = 0f;

            foreach (var receiver in receivers)
            {
                if (!receiver.Immutable)
                {
                    totalVolume += receiver.Volume;
                }
            }

            float?sourceHeatCapacity = null;
            var   buffer             = new float[Atmospherics.AdjustedNumberOfGases];

            foreach (var receiver in receivers)
            {
                if (receiver.Immutable)
                {
                    continue;
                }

                var fraction = receiver.Volume / totalVolume;

                // Set temperature, if necessary.
                if (MathF.Abs(receiver.Temperature - source.Temperature) > Atmospherics.MinimumTemperatureDeltaToConsider)
                {
                    // Often this divides a pipe net into new and completely empty pipe nets
                    if (receiver.TotalMoles == 0)
                    {
                        receiver.Temperature = source.Temperature;
                    }
                    else
                    {
                        sourceHeatCapacity ??= GetHeatCapacity(source);
                        var receiverHeatCapacity = GetHeatCapacity(receiver);
                        var combinedHeatCapacity = receiverHeatCapacity + sourceHeatCapacity.Value * fraction;
                        if (combinedHeatCapacity > 0f)
                        {
                            receiver.Temperature = (GetThermalEnergy(source, sourceHeatCapacity.Value * fraction) + GetThermalEnergy(receiver, receiverHeatCapacity)) / combinedHeatCapacity;
                        }
                    }
                }

                // transfer moles
                NumericsHelpers.Multiply(source.Moles, fraction, buffer);
                NumericsHelpers.Add(receiver.Moles, buffer);
            }
        }
        public void Update(GasMixture air, float frameDelta, AtmosphereSystem atmosphereSystem)
        {
            if (_temperatureComponent != null)
            {
                var temperatureDelta = air.Temperature - _temperatureComponent.CurrentTemperature;
                var tileHeatCapacity = atmosphereSystem.GetHeatCapacity(air);
                var heat             = temperatureDelta * (tileHeatCapacity * _temperatureComponent.HeatCapacity / (tileHeatCapacity + _temperatureComponent.HeatCapacity));
                _temperatureComponent.ReceiveHeat(heat);
                _temperatureComponent.Update();
            }

            _barotraumaComponent?.Update(air.Pressure);

            _flammableComponent?.Update(air);
        }
        public void ScrubInto(GasMixture mixture, GasMixture destination, IReadOnlyCollection <Gas> filterGases)
        {
            var buffer = new GasMixture(mixture.Volume)
            {
                Temperature = mixture.Temperature
            };

            foreach (var gas in filterGases)
            {
                buffer.AdjustMoles(gas, mixture.GetMoles(gas));
                mixture.SetMoles(gas, 0f);
            }

            Merge(destination, buffer);
        }
        /// <summary>
        /// Mix air from a gas container into a pipe net.
        /// Useful for anything that uses connector ports.
        /// </summary>
        public void MixContainerWithPipeNet(GasMixture containerAir, GasMixture pipeNetAir)
        {
            var buffer = new GasMixture(pipeNetAir.Volume + containerAir.Volume);

            _atmosphereSystem.Merge(buffer, pipeNetAir);
            _atmosphereSystem.Merge(buffer, containerAir);

            pipeNetAir.Clear();
            _atmosphereSystem.Merge(pipeNetAir, buffer);
            pipeNetAir.Multiply(pipeNetAir.Volume / buffer.Volume);

            containerAir.Clear();
            _atmosphereSystem.Merge(containerAir, buffer);
            containerAir.Multiply(containerAir.Volume / buffer.Volume);
        }
Beispiel #29
0
        private void OnBeforeUnanchored(EntityUid uid, AtmosUnsafeUnanchorComponent component, BeforeUnanchoredEvent args)
        {
            if (!component.Enabled || !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodes))
            {
                return;
            }

            if (!component.Owner.Transform.Coordinates.TryGetTileAtmosphere(out var environment))
            {
                environment = null;
            }

            var environmentPressure    = environment?.Air?.Pressure ?? 0f;
            var environmentVolume      = environment?.Air?.Volume ?? Atmospherics.CellVolume;
            var environmentTemperature = environment?.Air?.Volume ?? Atmospherics.TCMB;

            var lost      = 0f;
            var timesLost = 0;

            foreach (var node in nodes.Nodes.Values)
            {
                if (node is not PipeNode pipe)
                {
                    continue;
                }

                var difference = pipe.Air.Pressure - environmentPressure;
                lost += difference * environmentVolume / (environmentTemperature * Atmospherics.R);
                timesLost++;
            }

            var sharedLoss = lost / timesLost;
            var buffer     = new GasMixture();

            var atmosphereSystem = Get <AtmosphereSystem>();

            foreach (var node in nodes.Nodes.Values)
            {
                if (node is not PipeNode pipe)
                {
                    continue;
                }

                atmosphereSystem.Merge(buffer, pipe.Air.Remove(sharedLoss));
            }

            environment?.AssumeAir(buffer);
        }
        public ReactionResult React(GasMixture mixture, IGasMixtureHolder?holder)
        {
            var reaction    = ReactionResult.NoReaction;
            var temperature = mixture.Temperature;
            var energy      = GetThermalEnergy(mixture);

            foreach (var prototype in GasReactions)
            {
                if (energy < prototype.MinimumEnergyRequirement ||
                    temperature < prototype.MinimumTemperatureRequirement ||
                    temperature > prototype.MaximumTemperatureRequirement)
                {
                    continue;
                }

                var doReaction = true;
                for (var i = 0; i < prototype.MinimumRequirements.Length; i++)
                {
                    if (i > Atmospherics.TotalNumberOfGases)
                    {
                        throw new IndexOutOfRangeException("Reaction Gas Minimum Requirements Array Prototype exceeds total number of gases!");
                    }

                    var req = prototype.MinimumRequirements[i];

                    if (!(mixture.GetMoles(i) < req))
                    {
                        continue;
                    }
                    doReaction = false;
                    break;
                }

                if (!doReaction)
                {
                    continue;
                }

                reaction = prototype.React(mixture, holder, this);
                if (reaction.HasFlag(ReactionResult.StopReactions))
                {
                    break;
                }
            }

            return(reaction);
        }