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. } } }
/// <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); }
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); }
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); } }
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); } }
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); } }
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); } }
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); } } }
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); } } }
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); } }
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); }
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); }