public override void Update(float frameTime)
        {
            base.Update(frameTime);
            // Disease pool
            _poolAccumulator += frameTime;

            if (_poolAccumulator > _poolRepickTime.TotalSeconds)
            {
                _poolAccumulator = 0f;
                _poolDisease     = _random.Pick(MiasmaDiseasePool);
            }

            // Rotting
            foreach (var(rotting, perishable) in EntityQuery <RottingComponent, PerishableComponent>())
            {
                if (!perishable.Progressing)
                {
                    continue;
                }

                perishable.DeathAccumulator += frameTime;
                if (perishable.DeathAccumulator < perishable.RotAfter.TotalSeconds)
                {
                    continue;
                }

                perishable.RotAccumulator += frameTime;
                if (perishable.RotAccumulator < _rotUpdateRate) // This is where it starts to get noticable on larger animals, no need to run every second
                {
                    continue;
                }

                perishable.RotAccumulator -= _rotUpdateRate;

                EnsureComp <FliesComponent>(perishable.Owner);

                if (rotting.DealDamage)
                {
                    DamageSpecifier damage = new();
                    damage.DamageDict.Add("Blunt", 0.3);    // Slowly accumulate enough to gib after like half an hour
                    damage.DamageDict.Add("Cellular", 0.3); // Cloning rework might use this eventually

                    _damageableSystem.TryChangeDamage(perishable.Owner, damage, true, true);
                }

                if (!TryComp <PhysicsComponent>(perishable.Owner, out var physics))
                {
                    continue;
                }
                // We need a way to get the mass of the mob alone without armor etc in the future

                float molRate = perishable.MolsPerSecondPerUnitMass * _rotUpdateRate;

                var transform = Transform(perishable.Owner);
                var indices   = _transformSystem.GetGridOrMapTilePosition(perishable.Owner);

                var tileMix = _atmosphereSystem.GetTileMixture(transform.GridUid, null, indices, true);
                tileMix?.AdjustMoles(Gas.Miasma, molRate * physics.FixturesMass);
            }
        }
        private void OnUnanchorAttempt(EntityUid uid, AtmosUnsafeUnanchorComponent component, UnanchorAttemptEvent args)
        {
            if (!component.Enabled || !EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodes))
            {
                return;
            }

            if (_atmosphereSystem.GetTileMixture(EntityManager.GetComponent <TransformComponent>(component.Owner).Coordinates) is not {
            } environment)
            {
                return;
            }

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

                if ((pipe.Air.Pressure - environment.Pressure) > 2 * Atmospherics.OneAtmosphere)
                {
                    args.Delay += 1.5f;
                    _popupSystem.PopupCursor(Loc.GetString("comp-atmos-unsafe-unanchor-warning"), Filter.Entities(args.User));
                    return; // Show the warning only once.
                }
            }
        }
Beispiel #3
0
    /// <summary>
    ///     Tries to find an air mixture to inhale from, then inhales from it.
    /// </summary>
    public void Inhale(EntityUid uid, float frameTime,
                       LungComponent?lung      = null,
                       MechanismComponent?mech = null)
    {
        if (!Resolve(uid, ref lung, ref mech))
        {
            return;
        }

        // TODO Jesus Christ make this event based.
        if (mech.Body != null &&
            EntityManager.TryGetComponent((mech.Body).Owner, out InternalsComponent? internals) &&
            internals.BreathToolEntity != null &&
            internals.GasTankEntity != null &&
            EntityManager.TryGetComponent(internals.BreathToolEntity, out BreathToolComponent? breathTool) &&
            breathTool.IsFunctional &&
            EntityManager.TryGetComponent(internals.GasTankEntity, out GasTankComponent? gasTank))
        {
            TakeGasFrom(uid, frameTime, gasTank.RemoveAirVolume(Atmospherics.BreathVolume), lung);
            return;
        }

        if (_atmosSys.GetTileMixture(EntityManager.GetComponent <TransformComponent>(uid).Coordinates, true) is not {
        } tileAir)
        {
            return;
        }

        TakeGasFrom(uid, frameTime, tileAir, lung);
    }
Beispiel #4
0
        private void OnVentScrubberUpdated(EntityUid uid, GasVentScrubberComponent scrubber, AtmosDeviceUpdateEvent args)
        {
            var appearance = scrubber.Owner.GetComponentOrNull <AppearanceComponent>();

            if (scrubber.Welded)
            {
                appearance?.SetData(ScrubberVisuals.State, ScrubberState.Welded);
                return;
            }

            if (!scrubber.Enabled ||
                !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) ||
                !nodeContainer.TryGetNode(scrubber.OutletName, out PipeNode? outlet))
            {
                appearance?.SetData(ScrubberVisuals.State, ScrubberState.Off);
                return;
            }

            var environment = _atmosphereSystem.GetTileMixture(scrubber.Owner.Transform.Coordinates, true);

            Scrub(_atmosphereSystem, scrubber, appearance, environment, outlet);

            if (!scrubber.WideNet)
            {
                return;
            }

            // Scrub adjacent tiles too.
            foreach (var adjacent in _atmosphereSystem.GetAdjacentTileMixtures(scrubber.Owner.Transform.Coordinates, false, true))
            {
                Scrub(_atmosphereSystem, scrubber, null, adjacent, outlet);
            }
        }
        /// <summary>
        /// uses hunger to release a specific amount of miasma into the air. This heals the rat king
        /// and his servants through a specific metabolism.
        /// </summary>
        private void OnDomain(EntityUid uid, RatKingComponent component, RatKingDomainActionEvent args)
        {
            if (args.Handled)
            {
                return;
            }

            if (!TryComp <HungerComponent>(uid, out var hunger))
            {
                return;
            }

            //make sure the hunger doesn't go into the negatives
            if (hunger.CurrentHunger < component.HungerPerDomainUse)
            {
                _popup.PopupEntity(Loc.GetString("rat-king-too-hungry"), uid, Filter.Entities(uid));
                return;
            }
            args.Handled          = true;
            hunger.CurrentHunger -= component.HungerPerDomainUse;

            _popup.PopupEntity(Loc.GetString("rat-king-domain-popup"), uid, Filter.Pvs(uid));

            var transform = Transform(uid);
            var indices   = _xform.GetGridOrMapTilePosition(uid, transform);
            var tileMix   = _atmos.GetTileMixture(transform.GridUid, transform.MapUid, indices, true);

            tileMix?.AdjustMoles(Gas.Miasma, component.MolesMiasmaPerDomain);
        }
Beispiel #6
0
    private void OnActivate(EntityUid uid, GasArtifactComponent component, ArtifactActivatedEvent args)
    {
        if (component.SpawnGas == null || component.SpawnTemperature == null)
        {
            return;
        }

        var transform = Transform(uid);

        var environment = _atmosphereSystem.GetTileMixture(transform.Coordinates, true);

        if (environment == null)
        {
            return;
        }

        if (environment.Pressure >= component.MaxExternalPressure)
        {
            return;
        }

        var merger = new GasMixture(1)
        {
            Temperature = component.SpawnTemperature.Value
        };

        merger.SetMoles(component.SpawnGas.Value, component.SpawnAmount);

        _atmosphereSystem.Merge(environment, merger);
    }
    public override void Update(float frameTime)
    {
        base.Update(frameTime);
        var query = EntityManager.EntityQuery <ArtifactGasTriggerComponent, TransformComponent>();

        foreach (var(trigger, transform) in query)
        {
            var uid = trigger.Owner;

            if (trigger.ActivationGas == null)
            {
                continue;
            }

            var environment = _atmosphereSystem.GetTileMixture(transform.GridUid, transform.MapUid,
                                                               _transformSystem.GetGridOrMapTilePosition(uid, transform));

            if (environment == null)
            {
                continue;
            }

            // check if outside there is enough moles to activate artifact
            var moles = environment.GetMoles(trigger.ActivationGas.Value);
            if (moles < trigger.ActivationMoles)
            {
                continue;
            }

            _artifactSystem.TryActivateArtifact(trigger.Owner);
        }
    }
        /// <summary>
        /// uses hunger to release a specific amount of miasma into the air. This heals the rat king
        /// and his servants through a specific metabolism.
        /// </summary>
        private void OnDomain(EntityUid uid, RatKingComponent component, RatKingDomainActionEvent args)
        {
            if (args.Handled)
            {
                return;
            }

            if (!TryComp <HungerComponent>(uid, out var hunger))
            {
                return;
            }

            //make sure the hunger doesn't go into the negatives
            if (hunger.CurrentHunger < component.HungerPerDomainUse)
            {
                _popup.PopupEntity(Loc.GetString("rat-king-too-hungry"), uid, Filter.Entities(uid));
                return;
            }
            args.Handled          = true;
            hunger.CurrentHunger -= component.HungerPerDomainUse;

            _popup.PopupEntity(Loc.GetString("rat-king-domain-popup"), uid, Filter.Pvs(uid));

            var tileMix = _atmos.GetTileMixture(Transform(uid).Coordinates);

            if (tileMix != null)
            {
                tileMix.AdjustMoles(Gas.Miasma, component.MolesMiasmaPerDomain);
            }
        }
        private void OnOutletInjectorUpdated(EntityUid uid, GasOutletInjectorComponent injector, AtmosDeviceUpdateEvent args)
        {
            injector.Injecting = false;

            if (!injector.Enabled)
            {
                return;
            }

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

            if (!nodeContainer.TryGetNode(injector.InletName, out PipeNode? inlet))
            {
                return;
            }

            var environment = _atmosphereSystem.GetTileMixture(injector.Owner.Transform.Coordinates, true);

            if (environment == null)
            {
                return;
            }

            if (inlet.Air.Temperature > 0)
            {
                var transferMoles = inlet.Air.Pressure * injector.VolumeRate / (inlet.Air.Temperature * Atmospherics.R);

                var removed = inlet.Air.Remove(transferMoles);

                _atmosphereSystem.Merge(environment, removed);
            }
        }
Beispiel #10
0
        public override void Update(float frameTime)
        {
            base.Update(frameTime);
            foreach (var(rotting, perishable) in EntityQuery <RottingComponent, PerishableComponent>())
            {
                if (!perishable.Progressing)
                {
                    continue;
                }

                perishable.DeathAccumulator += frameTime;
                if (perishable.DeathAccumulator < perishable.RotAfter.TotalSeconds)
                {
                    continue;
                }

                perishable.RotAccumulator += frameTime;
                if (perishable.RotAccumulator < UpdateRate) // This is where it starts to get noticable on larger animals, no need to run every second
                {
                    continue;
                }

                perishable.RotAccumulator -= UpdateRate;

                EnsureComp <FliesComponent>(perishable.Owner);

                DamageSpecifier damage = new();
                damage.DamageDict.Add("Blunt", 0.3);    // Slowly accumulate enough to gib after like half an hour
                damage.DamageDict.Add("Cellular", 0.3); // Cloning rework might use this eventually

                _damageableSystem.TryChangeDamage(perishable.Owner, damage, true, true);

                if (!TryComp <PhysicsComponent>(perishable.Owner, out var physics))
                {
                    continue;
                }
                // We need a way to get the mass of the mob alone without armor etc in the future

                float molRate = perishable.MolsPerSecondPerUnitMass * UpdateRate;

                var tileMix = _atmosphereSystem.GetTileMixture(Transform(perishable.Owner).Coordinates);
                if (tileMix != null)
                {
                    tileMix.AdjustMoles(Gas.Miasma, molRate * physics.FixturesMass);
                }
            }
        }
        private void OnDeviceUpdated(EntityUid uid, PortableScrubberComponent component, AtmosDeviceUpdateEvent args)
        {
            if (!TryComp(uid, out AtmosDeviceComponent? device))
            {
                return;
            }

            var timeDelta = (float)(_gameTiming.CurTime - device.LastProcess).TotalSeconds;

            if (!component.Enabled)
            {
                return;
            }

            /// If we are on top of a connector port, empty into it.
            if (TryComp <NodeContainerComponent>(uid, out var nodeContainer) &&
                nodeContainer.TryGetNode(component.PortName, out PortablePipeNode? portableNode) &&
                portableNode.ConnectionsEnabled)
            {
                _atmosphereSystem.React(component.Air, portableNode);
                if (portableNode.NodeGroup is PipeNet {
                    NodeCount : > 1
                } net)
                {
                    _canisterSystem.MixContainerWithPipeNet(component.Air, net.Air);
                }
            }

            if (component.Full)
            {
                UpdateAppearance(uid, true, false);
                return;
            }

            var xform = Transform(uid);

            if (xform.GridUid == null)
            {
                return;
            }

            var position = _transformSystem.GetGridOrMapTilePosition(uid, xform);

            var environment = _atmosphereSystem.GetTileMixture(xform.GridUid, xform.MapUid, position, true);

            var running = Scrub(timeDelta, component, environment);

            UpdateAppearance(uid, false, running);
            /// We scrub once to see if we can and set the animation
            if (!running)
            {
                return;
            }
            /// widenet
            foreach (var adjacent in _atmosphereSystem.GetAdjacentTileMixtures(xform.GridUid.Value, position, false, true))
            {
                Scrub(timeDelta, component, environment);
            }
        }
        /// <summary>
        /// Completely dumps the content of the canister into the world.
        /// </summary>
        public void PurgeContents(EntityUid uid, GasCanisterComponent?canister = null, TransformComponent?transform = null)
        {
            if (!Resolve(uid, ref canister, ref transform))
            {
                return;
            }

            var environment = _atmosphereSystem.GetTileMixture(transform.Coordinates, true);

            if (environment is not null)
            {
                _atmosphereSystem.Merge(environment, canister.Air);
            }

            _adminLogSystem.Add(LogType.CanisterPurged, LogImpact.Medium, $"Canister {ToPrettyString(uid):canister} purged its contents of {canister.Air:gas} into the environment.");
            canister.Air.Clear();
        }
        private void OnVolumePumpUpdated(EntityUid uid, GasVolumePumpComponent pump, AtmosDeviceUpdateEvent args)
        {
            if (!pump.Enabled)
            {
                return;
            }

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

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

            if (!nodeContainer.TryGetNode(pump.InletName, out PipeNode? inlet) ||
                !nodeContainer.TryGetNode(pump.OutletName, out PipeNode? outlet))
            {
                return;
            }

            var inputStartingPressure  = inlet.Air.Pressure;
            var outputStartingPressure = outlet.Air.Pressure;

            // Pump mechanism won't do anything if the pressure is too high/too low unless you overclock it.
            if ((inputStartingPressure < pump.LowerThreshold) || (outputStartingPressure > pump.HigherThreshold) && !pump.Overclocked)
            {
                return;
            }

            // Overclocked pumps can only force gas a certain amount.
            if ((outputStartingPressure - inputStartingPressure > pump.OverclockThreshold) && pump.Overclocked)
            {
                return;
            }

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

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

            // Some of the gas from the mixture leaks when overclocked.
            if (pump.Overclocked)
            {
                var tile = _atmosphereSystem.GetTileMixture(pump.Owner.Transform.Coordinates, true);

                if (tile != null)
                {
                    var leaked = removed.RemoveRatio(pump.LeakRatio);
                    _atmosphereSystem.Merge(tile, leaked);
                }
            }

            outlet.AssumeAir(removed);
        }
        public void Inhale(EntityUid uid, SharedBodyComponent?body = null)
        {
            if (!Resolve(uid, ref body, false))
            {
                return;
            }

            var organs = _bodySystem.GetComponentsOnMechanisms <LungComponent>(uid, body);

            // Inhale gas
            var ev = new InhaleLocationEvent();

            RaiseLocalEvent(uid, ev, false);

            if (ev.Gas == null)
            {
                ev.Gas = _atmosSys.GetTileMixture(Transform(uid).Coordinates);
                if (ev.Gas == null)
                {
                    return;
                }
            }

            var ratio     = (Atmospherics.BreathVolume / ev.Gas.Volume);
            var actualGas = ev.Gas.RemoveRatio(ratio);

            var lungRatio = 1.0f / organs.Count;
            var gas       = organs.Count == 1 ? actualGas : actualGas.RemoveRatio(lungRatio);

            foreach (var(lung, _) in organs)
            {
                // Merge doesn't remove gas from the giver.
                _atmosSys.Merge(lung.Air, gas);
                _lungSystem.GasToReagent(lung.Owner, lung);
            }
        }
Beispiel #15
0
        private void OnOutletInjectorUpdated(EntityUid uid, GasOutletInjectorComponent injector, AtmosDeviceUpdateEvent args)
        {
            if (!injector.Enabled)
            {
                return;
            }

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

            if (!TryComp(uid, out AtmosDeviceComponent? device))
            {
                return;
            }

            if (!nodeContainer.TryGetNode(injector.InletName, out PipeNode? inlet))
            {
                return;
            }

            var environment = _atmosphereSystem.GetTileMixture(EntityManager.GetComponent <TransformComponent>(injector.Owner).Coordinates, true);

            if (environment == null)
            {
                return;
            }

            if (inlet.Air.Temperature < 0)
            {
                return;
            }

            if (environment.Pressure > injector.MaxPressure)
            {
                return;
            }

            var timeDelta = (float)(_gameTiming.CurTime - device.LastProcess).TotalSeconds;

            // TODO adjust ratio so that environment does not go above MaxPressure?
            var ratio   = MathF.Min(1f, timeDelta * injector.TransferRate / inlet.Air.Volume);
            var removed = inlet.Air.RemoveRatio(ratio);

            _atmosphereSystem.Merge(environment, removed);
        }
        private void OnVentScrubberUpdated(EntityUid uid, GasVentScrubberComponent scrubber, AtmosDeviceUpdateEvent args)
        {
            if (scrubber.Welded)
            {
                return;
            }

            if (!TryComp(uid, out AtmosDeviceComponent? device))
            {
                return;
            }

            var timeDelta = (float)(_gameTiming.CurTime - device.LastProcess).TotalSeconds;

            if (!scrubber.Enabled ||
                !EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) ||
                !nodeContainer.TryGetNode(scrubber.OutletName, out PipeNode? outlet))
            {
                return;
            }

            var xform = Transform(uid);

            if (xform.GridUid == null)
            {
                return;
            }

            var position = _transformSystem.GetGridOrMapTilePosition(uid, xform);

            var environment = _atmosphereSystem.GetTileMixture(xform.GridUid, xform.MapUid, position, true);

            Scrub(timeDelta, scrubber, environment, outlet);

            if (!scrubber.WideNet)
            {
                return;
            }

            // Scrub adjacent tiles too.
            foreach (var adjacent in _atmosphereSystem.GetAdjacentTileMixtures(xform.GridUid.Value, position, false, true))
            {
                Scrub(timeDelta, scrubber, adjacent, outlet);
            }
        }
Beispiel #17
0
        private void OnVentScrubberUpdated(EntityUid uid, GasVentScrubberComponent scrubber, AtmosDeviceUpdateEvent args)
        {
            var appearance = EntityManager.GetComponentOrNull <AppearanceComponent>(scrubber.Owner);

            if (scrubber.Welded)
            {
                appearance?.SetData(ScrubberVisuals.State, ScrubberState.Welded);
                _ambientSoundSystem.SetAmbience(scrubber.Owner, false);
                return;
            }

            if (!TryComp(uid, out AtmosDeviceComponent? device))
            {
                return;
            }

            var timeDelta = (float)(_gameTiming.CurTime - device.LastProcess).TotalSeconds;

            if (!scrubber.Enabled ||
                !EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) ||
                !nodeContainer.TryGetNode(scrubber.OutletName, out PipeNode? outlet))
            {
                appearance?.SetData(ScrubberVisuals.State, ScrubberState.Off);
                _ambientSoundSystem.SetAmbience(scrubber.Owner, false);
                return;
            }
            _ambientSoundSystem.SetAmbience(scrubber.Owner, true);

            var environment = _atmosphereSystem.GetTileMixture(EntityManager.GetComponent <TransformComponent>(scrubber.Owner).Coordinates, true);

            Scrub(timeDelta, scrubber, appearance, environment, outlet);

            if (!scrubber.WideNet)
            {
                return;
            }

            // Scrub adjacent tiles too.
            foreach (var adjacent in _atmosphereSystem.GetAdjacentTileMixtures(EntityManager.GetComponent <TransformComponent>(scrubber.Owner).Coordinates, false, true))
            {
                Scrub(timeDelta, scrubber, null, adjacent, outlet);
            }
        }
Beispiel #18
0
        private void OnPassiveVentUpdated(EntityUid uid, GasPassiveVentComponent vent, AtmosDeviceUpdateEvent args)
        {
            var environment = _atmosphereSystem.GetTileMixture(EntityManager.GetComponent <TransformComponent>(vent.Owner).Coordinates, true);

            if (environment == null)
            {
                return;
            }

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

            if (!nodeContainer.TryGetNode(vent.InletName, out PipeNode? inlet))
            {
                return;
            }

            var environmentPressure = environment.Pressure;
            var pressureDelta       = MathF.Abs(environmentPressure - inlet.Air.Pressure);

            if ((environment.Temperature > 0 || inlet.Air.Temperature > 0) && pressureDelta > 0.5f)
            {
                if (environmentPressure < inlet.Air.Pressure)
                {
                    var airTemperature = environment.Temperature > 0 ? environment.Temperature : inlet.Air.Temperature;
                    var transferMoles  = pressureDelta * environment.Volume / (airTemperature * Atmospherics.R);
                    var removed        = inlet.Air.Remove(transferMoles);
                    _atmosphereSystem.Merge(environment, removed);
                }
                else
                {
                    var airTemperature = inlet.Air.Temperature > 0 ? inlet.Air.Temperature : environment.Temperature;
                    var outputVolume   = inlet.Air.Volume;
                    var transferMoles  = (pressureDelta * outputVolume) / (airTemperature * Atmospherics.R);
                    transferMoles = MathF.Min(transferMoles, environment.TotalMoles * inlet.Air.Volume / environment.Volume);
                    var removed = environment.Remove(transferMoles);
                    _atmosphereSystem.Merge(inlet.Air, removed);
                }
            }
        }
Beispiel #19
0
    private void OnActivate(EntityUid uid, TemperatureArtifactComponent component, ArtifactActivatedEvent args)
    {
        var transform = Transform(uid);

        var center = _atmosphereSystem.GetTileMixture(transform.Coordinates, true);

        if (center == null)
        {
            return;
        }
        UpdateTileTemperature(component, center);

        if (component.EffectAdjacentTiles)
        {
            var adjacent = _atmosphereSystem.GetAdjacentTileMixtures(transform.Coordinates, invalidate: true);
            foreach (var mixture in adjacent)
            {
                UpdateTileTemperature(component, mixture);
            }
        }
    }
Beispiel #20
0
    public override void Update(float frameTime)
    {
        base.Update(frameTime);

        var query = EntityManager.EntityQuery <ArtifactHeatTriggerComponent, TransformComponent, ArtifactComponent>();

        foreach (var(trigger, transform, artifact) in query)
        {
            var environment = _atmosphereSystem.GetTileMixture(transform.Coordinates);
            if (environment == null)
            {
                continue;
            }

            if (environment.Temperature < trigger.ActivationTemperature)
            {
                continue;
            }

            _artifactSystem.TryActivateArtifact(trigger.Owner, component: artifact);
        }
    }
Beispiel #21
0
        public override void Update(float frameTime)
        {
            base.Update(frameTime);

            if (!RuleStarted)
            {
                return;
            }

            if (Elapsed > _endAfter)
            {
                ForceEndSelf();
                return;
            }

            _timeUntilLeak -= frameTime;

            if (_timeUntilLeak > 0f)
            {
                return;
            }
            _timeUntilLeak += LeakCooldown;

            if (!_foundTile ||
                _targetGrid == default ||
                EntityManager.Deleted(_targetGrid) ||
                !_atmosphere.IsSimulatedGrid(_targetGrid))
            {
                ForceEndSelf();
                return;
            }

            var environment = _atmosphere.GetTileMixture(_targetGrid, null, _targetTile, true);

            environment?.AdjustMoles(_leakGas, LeakCooldown * _molesPerSecond);
        }
        private bool CheckMinerOperation(GasMinerComponent miner, [NotNullWhen(true)] out GasMixture?environment)
        {
            environment = _atmosphereSystem.GetTileMixture(EntityManager.GetComponent <TransformComponent>(miner.Owner).Coordinates, true);

            // Space.
            if (_atmosphereSystem.IsTileSpace(EntityManager.GetComponent <TransformComponent>(miner.Owner).Coordinates))
            {
                miner.Broken = true;
                return(false);
            }

            // Air-blocked location.
            if (environment == null)
            {
                miner.Broken = true;
                return(false);
            }

            // External pressure above threshold.
            if (!float.IsInfinity(miner.MaxExternalPressure) &&
                environment.Pressure > miner.MaxExternalPressure - miner.SpawnAmount * miner.SpawnTemperature * Atmospherics.R / environment.Volume)
            {
                miner.Broken = true;
                return(false);
            }

            // External gas amount above threshold.
            if (!float.IsInfinity(miner.MaxExternalAmount) && environment.TotalMoles > miner.MaxExternalAmount)
            {
                miner.Broken = true;
                return(false);
            }

            miner.Broken = false;
            return(true);
        }
Beispiel #23
0
        private void OnGasVentPumpUpdated(EntityUid uid, GasVentPumpComponent vent, AtmosDeviceUpdateEvent args)
        {
            //Bingo waz here
            if (vent.Welded)
            {
                return;
            }

            var nodeName = vent.PumpDirection switch
            {
                VentPumpDirection.Releasing => vent.Inlet,
                VentPumpDirection.Siphoning => vent.Outlet,
                _ => throw new ArgumentOutOfRangeException()
            };

            if (!vent.Enabled ||
                !TryComp(uid, out AtmosDeviceComponent? device) ||
                !TryComp(uid, out NodeContainerComponent? nodeContainer) ||
                !nodeContainer.TryGetNode(nodeName, out PipeNode? pipe))
            {
                return;
            }

            var environment = _atmosphereSystem.GetTileMixture(EntityManager.GetComponent <TransformComponent>(vent.Owner).Coordinates, true);

            // We're in an air-blocked tile... Do nothing.
            if (environment == null)
            {
                return;
            }

            var timeDelta     = (_gameTiming.CurTime - device.LastProcess).TotalSeconds;
            var pressureDelta = (float)timeDelta * vent.TargetPressureChange;

            if (vent.PumpDirection == VentPumpDirection.Releasing && pipe.Air.Pressure > 0)
            {
                if (environment.Pressure > vent.MaxPressure)
                {
                    return;
                }

                if ((vent.PressureChecks & VentPressureBound.ExternalBound) != 0)
                {
                    pressureDelta = MathF.Min(pressureDelta, vent.ExternalPressureBound - environment.Pressure);
                }

                if (pressureDelta <= 0)
                {
                    return;
                }

                // how many moles to transfer to change external pressure by pressureDelta
                // (ignoring temperature differences because I am lazy)
                var transferMoles = pressureDelta * environment.Volume / (pipe.Air.Temperature * Atmospherics.R);

                // limit transferMoles so the source doesn't go below its bound.
                if ((vent.PressureChecks & VentPressureBound.InternalBound) != 0)
                {
                    var internalDelta = pipe.Air.Pressure - vent.InternalPressureBound;

                    if (internalDelta <= 0)
                    {
                        return;
                    }

                    var maxTransfer = internalDelta * pipe.Air.Volume / (pipe.Air.Temperature * Atmospherics.R);
                    transferMoles = MathF.Min(transferMoles, maxTransfer);
                }

                _atmosphereSystem.Merge(environment, pipe.Air.Remove(transferMoles));
            }
            else if (vent.PumpDirection == VentPumpDirection.Siphoning && environment.Pressure > 0)
            {
                if (pipe.Air.Pressure > vent.MaxPressure)
                {
                    return;
                }

                if ((vent.PressureChecks & VentPressureBound.InternalBound) != 0)
                {
                    pressureDelta = MathF.Min(pressureDelta, vent.InternalPressureBound - pipe.Air.Pressure);
                }

                if (pressureDelta <= 0)
                {
                    return;
                }

                // how many moles to transfer to change internal pressure by pressureDelta
                // (ignoring temperature differences because I am lazy)
                var transferMoles = pressureDelta * pipe.Air.Volume / (environment.Temperature * Atmospherics.R);

                // limit transferMoles so the source doesn't go below its bound.
                if ((vent.PressureChecks & VentPressureBound.ExternalBound) != 0)
                {
                    var externalDelta = environment.Pressure - vent.ExternalPressureBound;

                    if (externalDelta <= 0)
                    {
                        return;
                    }

                    var maxTransfer = externalDelta * environment.Volume / (environment.Temperature * Atmospherics.R);

                    transferMoles = MathF.Min(transferMoles, maxTransfer);
                }

                _atmosphereSystem.Merge(pipe.Air, environment.Remove(transferMoles));
            }
        }
        private void OnGasDualPortVentPumpUpdated(EntityUid uid, GasDualPortVentPumpComponent vent, AtmosDeviceUpdateEvent args)
        {
            var appearance = vent.Owner.GetComponentOrNull <AppearanceComponent>();

            if (vent.Welded)
            {
                appearance?.SetData(VentPumpVisuals.State, VentPumpState.Welded);
                return;
            }

            if (!vent.Enabled ||
                !EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) ||
                !nodeContainer.TryGetNode(vent.InletName, out PipeNode? inlet) ||
                !nodeContainer.TryGetNode(vent.OutletName, out PipeNode? outlet))
            {
                appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off);
                return;
            }

            var environment = _atmosphereSystem.GetTileMixture(vent.Owner.Transform.Coordinates, true);

            // We're in an air-blocked tile... Do nothing.
            if (environment == null)
            {
                appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off);
                return;
            }

            if (vent.PumpDirection == VentPumpDirection.Releasing)
            {
                appearance?.SetData(VentPumpVisuals.State, VentPumpState.Out);
                var pressureDelta = 10000f;

                if ((vent.PressureChecks & DualPortVentPressureBound.ExternalBound) != 0)
                {
                    pressureDelta = MathF.Min(pressureDelta, (vent.ExternalPressureBound - environment.Pressure));
                }

                if ((vent.PressureChecks & DualPortVentPressureBound.InputMinimum) != 0)
                {
                    pressureDelta = MathF.Min(pressureDelta, (inlet.Air.Pressure - vent.InputPressureMin));
                }

                if (pressureDelta > 0 && inlet.Air.Temperature > 0)
                {
                    var transferMoles = pressureDelta * environment.Volume / inlet.Air.Temperature * Atmospherics.R;
                    var removed       = inlet.Air.Remove(transferMoles);
                    _atmosphereSystem.Merge(environment, removed);
                }
            }
            else if (vent.PumpDirection == VentPumpDirection.Siphoning && environment.Pressure > 0f)
            {
                appearance?.SetData(VentPumpVisuals.State, VentPumpState.In);
                var ourMultiplier = outlet.Air.Volume / environment.Temperature * Atmospherics.R;
                var molesDelta    = 10000 * ourMultiplier;

                if ((vent.PressureChecks & DualPortVentPressureBound.ExternalBound) != 0)
                {
                    molesDelta =
                        MathF.Min(molesDelta,
                                  (environment.Pressure - vent.OutputPressureMax) * environment.Volume / (environment.Temperature * Atmospherics.R));
                }

                if ((vent.PressureChecks & DualPortVentPressureBound.InputMinimum) != 0)
                {
                    molesDelta = MathF.Min(molesDelta, (vent.InputPressureMin - outlet.Air.Pressure) * ourMultiplier);
                }

                if (molesDelta > 0)
                {
                    var removed = environment.Remove(molesDelta);

                    _atmosphereSystem.Merge(outlet.Air, removed);
                }
            }
        }
        private void OnCanisterUpdated(EntityUid uid, GasCanisterComponent canister, AtmosDeviceUpdateEvent args)
        {
            if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) ||
                !ComponentManager.TryGetComponent(uid, out AppearanceComponent? appearance))
            {
                return;
            }

            if (!nodeContainer.TryGetNode(canister.PortName, out PortablePipeNode? portNode))
            {
                return;
            }

            _atmosphereSystem.React(canister.Air, portNode);

            if (portNode.NodeGroup is PipeNet {
                NodeCount: > 1
            } net)
            {
                var buffer = new GasMixture(net.Air.Volume + canister.Air.Volume);

                _atmosphereSystem.Merge(buffer, net.Air);
                _atmosphereSystem.Merge(buffer, canister.Air);

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

                canister.Air.Clear();
                _atmosphereSystem.Merge(canister.Air, buffer);
                canister.Air.Multiply(canister.Air.Volume / buffer.Volume);
            }

            // Release valve is open, release gas.
            if (canister.ReleaseValve)
            {
                if (!ComponentManager.TryGetComponent(uid, out ContainerManagerComponent? containerManager) ||
                    !containerManager.TryGetContainer(canister.ContainerName, out var container))
                {
                    return;
                }

                if (container.ContainedEntities.Count > 0)
                {
                    var gasTank = container.ContainedEntities[0].GetComponent <GasTankComponent>();
                    _atmosphereSystem.ReleaseGasTo(canister.Air, gasTank.Air, canister.ReleasePressure);
                }
                else
                {
                    var environment = _atmosphereSystem.GetTileMixture(canister.Owner.Transform.Coordinates, true);
                    _atmosphereSystem.ReleaseGasTo(canister.Air, environment, canister.ReleasePressure);
                }
            }

            DirtyUI(uid);

            // If last pressure is very close to the current pressure, do nothing.
            if (MathHelper.CloseTo(canister.Air.Pressure, canister.LastPressure))
            {
                return;
            }

            canister.LastPressure = canister.Air.Pressure;

            if (canister.Air.Pressure < 10)
            {
                appearance.SetData(GasCanisterVisuals.PressureState, 0);
            }
            else if (canister.Air.Pressure < Atmospherics.OneAtmosphere)
            {
                appearance.SetData(GasCanisterVisuals.PressureState, 1);
            }
            else if (canister.Air.Pressure < (15 * Atmospherics.OneAtmosphere))
            {
                appearance.SetData(GasCanisterVisuals.PressureState, 2);
            }
            else
            {
                appearance.SetData(GasCanisterVisuals.PressureState, 3);
            }
        }
        public void ExitDisposals(EntityUid uid, DisposalHolderComponent?holder = null, TransformComponent?holderTransform = null)
        {
            if (!Resolve(uid, ref holder, ref holderTransform))
            {
                return;
            }
            if (holder.IsExitingDisposals)
            {
                Logger.ErrorS("c.s.disposal.holder", "Tried exiting disposals twice. This should never happen.");
                return;
            }
            holder.IsExitingDisposals = true;

            // Check for a disposal unit to throw them into and then eject them from it.
            // *This ejection also makes the target not collide with the unit.*
            // *This is on purpose.*

            DisposalUnitComponent?duc = null;

            if (_mapManager.TryGetGrid(holderTransform.GridUid, out var grid))
            {
                foreach (var contentUid in grid.GetLocal(holderTransform.Coordinates))
                {
                    if (EntityManager.TryGetComponent(contentUid, out duc))
                    {
                        break;
                    }
                }
            }

            foreach (var entity in holder.Container.ContainedEntities.ToArray())
            {
                RemComp <BeingDisposedComponent>(entity);

                if (EntityManager.TryGetComponent(entity, out IPhysBody? physics))
                {
                    physics.CanCollide = true;
                }

                var meta = MetaData(entity);
                holder.Container.ForceRemove(entity, EntityManager, meta);

                var xform = Transform(entity);
                if (xform.ParentUid != uid)
                {
                    continue;
                }

                if (duc != null)
                {
                    duc.Container.Insert(entity, EntityManager, xform, meta: meta);
                }
                else
                {
                    xform.AttachParentToContainerOrGrid(EntityManager);
                }
            }

            if (duc != null)
            {
                _disposalUnitSystem.TryEjectContents(duc);
            }

            if (_atmosphereSystem.GetTileMixture(holderTransform.Coordinates, true) is {} environment)
            {
                _atmosphereSystem.Merge(environment, holder.Air);
                holder.Air.Clear();
            }

            EntityManager.DeleteEntity(uid);
        }