public static bool Intersection(Vector2 aStart, Vector2 aEnd, Vector2 bStart, Vector2 bEnd, out Vector2 intersection) { Vector2 aSize = aEnd - aStart, bSize = bEnd - bStart; var cross = aSize.X * bSize.Y - aSize.Y * bSize.X; // ReSharper disable once CompareOfFloatsByEqualityOperator if (cross == 0f) { intersection = default; return(false); } var crossReciprocal = 1.0f / cross; var distStart = bStart - aStart; var negDistStartY = -distStart.Y; var checkA = MathF.FusedMultiplyAdd(distStart.X, aSize.Y, negDistStartY * aSize.X) * crossReciprocal; var checkB = MathF.FusedMultiplyAdd(distStart.X, bSize.Y, negDistStartY * bSize.X) * crossReciprocal; if (checkA < 0 || checkB < 0 || checkA > 1 || checkB > 1) { intersection = default; return(false); } intersection = new Vector2( MathF.FusedMultiplyAdd(checkB, aSize.X, aStart.X), MathF.FusedMultiplyAdd(checkB, aSize.Y, aStart.Y) ); return(true); }
public override void Render(DrawingHandleWorld handle) { if (onGrid) { const int ppm = EyeManager.PixelsPerMeter; var viewportSize = (Vector2)pManager._clyde.ScreenSize; var position = pManager.eyeManager.ScreenToMap(Vector2.Zero); var gridstartx = (float)MathF.Round(position.X / snapSize, MidpointRounding.AwayFromZero) * snapSize; var gridstarty = (float)MathF.Round(position.Y / snapSize, MidpointRounding.AwayFromZero) * snapSize; var gridstart = pManager.eyeManager.WorldToScreen( new Vector2( //Find snap grid closest to screen origin and convert back to screen coords gridstartx, gridstarty)); for (var a = gridstart.X; a < viewportSize.X; a += snapSize * ppm) //Iterate through screen creating gridlines { var from = ScreenToWorld(new Vector2(a, 0)); var to = ScreenToWorld(new Vector2(a, viewportSize.Y)); handle.DrawLine(from, to, new Color(0, 0, 1f)); } for (var a = gridstart.Y; a < viewportSize.Y; a += snapSize * ppm) { var from = ScreenToWorld(new Vector2(0, a)); var to = ScreenToWorld(new Vector2(viewportSize.X, a)); handle.DrawLine(from, to, new Color(0, 0, 1f)); } } // Draw grid BELOW the ghost. base.Render(handle); }
private void HandleDecompressionFloorRip(float sum) { if (sum > 20 && _robustRandom.Prob(MathF.Clamp(sum / 100, 0.005f, 0.5f))) { _gridAtmosphereComponent.PryTile(GridIndices); } }
public static bool ContainsPoint(this ReadOnlySpan <Vector2> poly, Vector2 point) { var result = false; var j = poly.Length - 1; var pY = point.Y; var pX = point.X; for (var i = 0; i < poly.Length; i++) { var iY = poly[i].Y; var jY = poly[j].Y; var iX = poly[i].X; var jX = poly[j].X; if (iY < pY && jY >= pY || jY < pY && iY >= pY && MathF.FusedMultiplyAdd( (pY - iY) / (jY - iY), jX - iX, iX ) < pX) { result = !result; } j = i; } return(result); }
public static float Clamp01(float value) { /* * if (value < 0F) * return 0F; * * if (value > 1F) * return 1F; * * return value; */ return(MathF.Clamp(value, 0, 1)); }
/// <summary> /// Knocks down the mob, making it fall to the ground. /// </summary> /// <param name="seconds">How many seconds the mob will stay on the ground</param> public void Knockdown(float seconds) { seconds = MathF.Min(_knockdownTimer + (seconds * KnockdownTimeModifier), _knockdownCap); if (seconds <= 0f) { return; } StandingStateHelper.Down(Owner); _knockdownTimer = seconds; _lastStun = _gameTiming.CurTime; SetStatusEffect(); Dirty(); }
public override void AlignPlacementMode(ScreenCoordinates mouseScreen) { MouseCoords = ScreenToCursorGrid(mouseScreen); snapSize = pManager.MapManager.GetGrid(MouseCoords.GridID).SnapSize; //Find snap size. GridDistancing = snapSize; onGrid = true; var mouselocal = new Vector2( //Round local coordinates onto the snap grid (float)MathF.Round(MouseCoords.X / snapSize, MidpointRounding.AwayFromZero) * snapSize, (float)MathF.Round(MouseCoords.Y / snapSize, MidpointRounding.AwayFromZero) * snapSize); //Convert back to original world and screen coordinates after applying offset MouseCoords = new GridCoordinates( mouselocal + new Vector2(pManager.PlacementOffset.X, pManager.PlacementOffset.Y), MouseCoords.GridID); }
/// <summary> /// Stuns the entity, disallowing it from doing many interactions temporarily. /// </summary> /// <param name="seconds">How many seconds the mob will stay stunned</param> public void Stun(float seconds) { seconds = MathF.Min(_stunnedTimer + (seconds * StunTimeModifier), _stunCap); if (seconds <= 0f) { return; } StandingStateHelper.DropAllItemsInHands(Owner, false); _stunnedTimer = seconds; _lastStun = _gameTiming.CurTime; SetStatusEffect(); Dirty(); }
protected override Vector2 CalculateMinimumSize() { var separation = ActualSeparation; var minWidth = 0f; var minHeight = 0f; var first = true; foreach (var child in Children) { if (!child.Visible) { continue; } var(childWidth, childHeight) = child.CombinedMinimumSize; if (Vertical) { minHeight += childHeight; if (!first) { minHeight += separation; } first = false; minWidth = MathF.Max(minWidth, childWidth); } else { minWidth += childWidth; if (!first) { minWidth += separation; } first = false; minHeight = MathF.Max(minHeight, childHeight); } } return(new Vector2(minWidth, minHeight)); }
public void ExperiencePressureDifference(int cycle, float pressureDifference, Direction direction, float pressureResistanceProbDelta, GridCoordinates throwTarget) { if (ControlledComponent == null) { return; } // TODO ATMOS stuns? var transform = ControlledComponent.Owner.Transform; var pressureComponent = ControlledComponent.Owner.GetComponent <MovedByPressureComponent>(); var maxForce = MathF.Sqrt(pressureDifference) * 2.25f; var moveProb = 100f; if (pressureComponent.PressureResistance > 0) { moveProb = MathF.Abs((pressureDifference / pressureComponent.PressureResistance * ProbabilityBasePercent) - ProbabilityOffset); } if (moveProb > ProbabilityOffset && _robustRandom.Prob(MathF.Min(moveProb / 100f, 1f)) && !float.IsPositiveInfinity(pressureComponent.MoveResist) && (!ControlledComponent.Anchored && (maxForce >= (pressureComponent.MoveResist * MoveForcePushRatio))) || (ControlledComponent.Anchored && (maxForce >= (pressureComponent.MoveResist * MoveForceForcePushRatio)))) { if (maxForce > ThrowForce && throwTarget != GridCoordinates.InvalidGrid) { var moveForce = MathF.Min(maxForce * MathF.Clamp(moveProb, 0, 100) / 100f, 50f); var pos = throwTarget.Position - transform.GridPosition.Position; LinearVelocity = pos * moveForce; } else { var moveForce = MathF.Min(maxForce * MathF.Clamp(moveProb, 0, 100) / 100f, 25f); LinearVelocity = direction.ToVec() * moveForce; } pressureComponent.LastHighPressureMovementAirCycle = cycle; } }
/// <summary> /// Throw an entity at the position of <paramref name="targetLoc"/> from <paramref name="sourceLoc"/>, /// without overshooting. /// </summary> /// <param name="thrownEnt">The entity to throw.</param> /// <param name="throwForceMax"> /// The MAXIMUM force to throw the entity with. /// Throw force increases with distance to target, this is the maximum force allowed. /// </param> /// <param name="targetLoc"> /// The target location to throw at. /// This function will try to land at this exact spot, /// if <paramref name="throwForceMax"/> is large enough to allow for it to be reached. /// </param> /// <param name="sourceLoc"> /// The position to start the throw from. /// </param> /// <param name="spread"> /// If true, slightly spread the actual throw angle. /// </param> /// <param name="throwSourceEnt"> /// The entity that did the throwing. An opposite impulse will be applied to this entity if passed in. /// </param> public static void ThrowTo(IEntity thrownEnt, float throwForceMax, GridCoordinates targetLoc, GridCoordinates sourceLoc, bool spread = false, IEntity throwSourceEnt = null) { var mapManager = IoCManager.Resolve <IMapManager>(); var timing = IoCManager.Resolve <IGameTiming>(); // Calculate the force necessary to land a throw based on throw duration, mass and distance. var distance = (targetLoc.ToMapPos(mapManager) - sourceLoc.ToMapPos(mapManager)).Length; var throwDuration = ThrownItemComponent.DefaultThrowTime; var mass = 1f; if (thrownEnt.TryGetComponent(out IPhysicsComponent physicsComponent)) { mass = physicsComponent.Mass; } var velocityNecessary = distance / throwDuration; var impulseNecessary = velocityNecessary * mass; var forceNecessary = impulseNecessary * (1f / timing.TickRate); // Then clamp it to the max force allowed and call Throw(). Throw(thrownEnt, MathF.Min(forceNecessary, throwForceMax), targetLoc, sourceLoc, spread, throwSourceEnt); }
/// <summary> /// Slows down the mob's walking/running speed temporarily /// </summary> /// <param name="seconds">How many seconds the mob will be slowed down</param> /// <param name="walkModifierOverride">Walk speed modifier. Set to 0 or negative for default value. (0.5f)</param> /// <param name="runModifierOverride">Run speed modifier. Set to 0 or negative for default value. (0.5f)</param> public void Slowdown(float seconds, float walkModifierOverride = 0f, float runModifierOverride = 0f) { seconds = MathF.Min(_slowdownTimer + (seconds * SlowdownTimeModifier), _slowdownCap); if (seconds <= 0f) { return; } WalkModifierOverride = walkModifierOverride; RunModifierOverride = runModifierOverride; _slowdownTimer = seconds; _lastStun = _gameTiming.CurTime; if (Owner.TryGetComponent(out MovementSpeedModifierComponent movement)) { movement.RefreshMovementSpeedModifiers(); } SetStatusEffect(); Dirty(); }
public static float Min(float a, float b, float c, float d) { return(MathF.Min(a, MathF.Min(b, MathF.Min(c, d)))); }
//[MethodImpl(MethodImplOptions.AggressiveInlining)] public void HighPressureMovements() { // TODO ATMOS finish this if (PressureDifference > 15) { if (_soundCooldown == 0) { EntitySystem.Get <AudioSystem>().PlayAtCoords("/Audio/Effects/space_wind.ogg", GridIndices.ToGridCoordinates(_mapManager, GridIndex), AudioHelpers.WithVariation(0.125f).WithVolume(MathF.Clamp(PressureDifference / 10, 10, 100))); } } foreach (var entity in _entityManager.GetEntitiesIntersecting(_mapManager.GetGrid(GridIndex).ParentMapId, Box2.UnitCentered.Translated(GridIndices))) { if (!entity.TryGetComponent(out ICollidableComponent physics) || !entity.TryGetComponent(out MovedByPressureComponent pressure)) { continue; } var pressureMovements = physics.EnsureController <HighPressureMovementController>(); if (pressure.LastHighPressureMovementAirCycle < _gridAtmosphereComponent.UpdateCounter) { pressureMovements.ExperiencePressureDifference(_gridAtmosphereComponent.UpdateCounter, PressureDifference, _pressureDirection, 0, PressureSpecificTarget?.GridIndices.ToGridCoordinates(_mapManager, GridIndex) ?? GridCoordinates.InvalidGrid); } } if (PressureDifference > 100) { // Do space wind graphics here! } _soundCooldown++; if (_soundCooldown > 75) { _soundCooldown = 0; } }
public static float Floor(float f) => MathF.Floor(f);
public bool Intersects(Box2 box, out float distance, out Vector2 hitPos) { hitPos = Vector2.Zero; distance = 0; var tmin = 0.0f; // set to -FLT_MAX to get first hit on line var tmax = float.MaxValue; // set to max distance ray can travel (for segment) const float epsilon = 1.0E-07f; // X axis slab { if (MathF.Abs(_direction.X) < epsilon) { // ray is parallel to this slab, it will never hit unless ray is inside box if (_position.X < MathF.Min(box.Left, box.Right) || _position.X > MathF.Max(box.Left, box.Right)) { return(false); } } // calculate intersection t value of ray with near and far plane of slab var ood = 1.0f / _direction.X; var t1 = (MathF.Min(box.Left, box.Right) - _position.X) * ood; var t2 = (MathF.Max(box.Left, box.Right) - _position.X) * ood; // Make t1 be the intersection with near plane, t2 with far plane if (t1 > t2) { MathHelper.Swap(ref t1, ref t2); } // Compute the intersection of slab intersection intervals tmin = MathF.Max(t1, tmin); tmax = MathF.Min(t2, tmax); // Is this Min (SE) or Max(Textbook) // Exit with no collision as soon as slab intersection becomes empty if (tmin > tmax) { return(false); } } // Y axis slab { if (MathF.Abs(_direction.Y) < epsilon) { // ray is parallel to this slab, it will never hit unless ray is inside box if (_position.Y < MathF.Min(box.Top, box.Bottom) || _position.Y > MathF.Max(box.Top, box.Bottom)) { return(false); } } // calculate intersection t value of ray with near and far plane of slab var ood = 1.0f / _direction.Y; var t1 = (MathF.Min(box.Top, box.Bottom) - _position.Y) * ood; var t2 = (MathF.Max(box.Top, box.Bottom) - _position.Y) * ood; // Make t1 be the intersection with near plane, t2 with far plane if (t1 > t2) { MathHelper.Swap(ref t1, ref t2); } // Compute the intersection of slab intersection intervals tmin = MathF.Max(t1, tmin); tmax = MathF.Min(t2, tmax); // Is this Min (SE) or Max(Textbook) // Exit with no collision as soon as slab intersection becomes empty if (tmin > tmax) { return(false); } } // Ray intersects all slabs. Return point and intersection t value hitPos = _position + _direction * tmin; distance = tmin; return(true); }
public static float InterpolateCubic(float preA, float a, float b, float postB, float t) { //return a + 0.5f * t * (b - preA + t * (2.0f * preA - 5.0f * a + 4.0f * b - postB + t * (3.0f * (a - b) + postB - preA))); return(MathF.CubicInterpolate(preA, a, b, postB, t)); }
public static float Lerp(float a, float b, float blend) { //return a + (b - a) * blend; return(MathF.Interpolate(a, b, blend)); }
//[MethodImpl(MethodImplOptions.AggressiveInlining)] public void EqualizePressureInZone(int cycleNum) { if (Air == null || (_tileAtmosInfo.LastCycle >= cycleNum)) { return; // Already done. } _tileAtmosInfo = new TileAtmosInfo(); var startingMoles = Air.TotalMoles; var runAtmos = false; // We need to figure if this is necessary foreach (var(direction, other) in _adjacentTiles) { if (other?.Air == null) { continue; } var comparisonMoles = other.Air.TotalMoles; if (!(MathF.Abs(comparisonMoles - startingMoles) > Atmospherics.MinimumMolesDeltaToMove)) { continue; } runAtmos = true; break; } if (!runAtmos) // There's no need so we don't bother. { _tileAtmosInfo.LastCycle = cycleNum; return; } var queueCycle = ++_gridAtmosphereComponent.EqualizationQueueCycleControl; var totalMoles = 0f; var tiles = new TileAtmosphere[Atmospherics.ZumosHardTileLimit]; tiles[0] = this; _tileAtmosInfo.LastQueueCycle = queueCycle; var tileCount = 1; for (var i = 0; i < tileCount; i++) { if (i > Atmospherics.ZumosHardTileLimit) { break; } var exploring = tiles[i]; if (i < Atmospherics.ZumosTileLimit) { var tileMoles = exploring.Air.TotalMoles; exploring._tileAtmosInfo.MoleDelta = tileMoles; totalMoles += tileMoles; } foreach (var(_, adj) in exploring._adjacentTiles) { if (adj?.Air == null) { continue; } if (adj._tileAtmosInfo.LastQueueCycle == queueCycle) { continue; } adj._tileAtmosInfo = new TileAtmosInfo(); adj._tileAtmosInfo.LastQueueCycle = queueCycle; if (tileCount < Atmospherics.ZumosHardTileLimit) { tiles[tileCount++] = adj; } if (adj.Air.Immutable) { // Looks like someone opened an airlock to space! ExplosivelyDepressurize(cycleNum); return; } } } if (tileCount > Atmospherics.ZumosTileLimit) { for (var i = Atmospherics.ZumosTileLimit; i < tileCount; i++) { //We unmark them. We shouldn't be pushing/pulling gases to/from them. var tile = tiles[i]; if (tile == null) { continue; } tiles[i]._tileAtmosInfo.LastQueueCycle = 0; } tileCount = Atmospherics.ZumosTileLimit; } //tiles = tiles.AsSpan().Slice(0, tileCount).ToArray(); // According to my benchmarks, this is much slower. Array.Resize(ref tiles, tileCount); var averageMoles = totalMoles / (tiles.Length); var giverTiles = new List <TileAtmosphere>(); var takerTiles = new List <TileAtmosphere>(); for (var i = 0; i < tileCount; i++) { var tile = tiles[i]; tile._tileAtmosInfo.LastCycle = cycleNum; tile._tileAtmosInfo.MoleDelta -= averageMoles; if (tile._tileAtmosInfo.MoleDelta > 0) { giverTiles.Add(tile); } else { takerTiles.Add(tile); } } var logN = MathF.Log2(tiles.Length); // Optimization - try to spread gases using an O(nlogn) algorithm that has a chance of not working first to avoid O(n^2) if (giverTiles.Count > logN && takerTiles.Count > logN) { // Even if it fails, it will speed up the next part. Array.Sort(tiles, (a, b) => a._tileAtmosInfo.MoleDelta.CompareTo(b._tileAtmosInfo.MoleDelta)); foreach (var tile in tiles) { tile._tileAtmosInfo.FastDone = true; if (!(tile._tileAtmosInfo.MoleDelta > 0)) { continue; } Direction eligibleAdjBits = 0; var amtEligibleAdj = 0; foreach (var direction in Cardinal) { if (!tile._adjacentTiles.TryGetValue(direction, out var tile2)) { continue; } // skip anything that isn't part of our current processing block. Original one didn't do this unfortunately, which probably cause some massive lag. if (tile2._tileAtmosInfo.FastDone || tile2._tileAtmosInfo.LastQueueCycle != queueCycle) { continue; } eligibleAdjBits |= direction; amtEligibleAdj++; } if (amtEligibleAdj <= 0) { continue; // Oof we've painted ourselves into a corner. Bad luck. Next part will handle this. } var molesToMove = tile._tileAtmosInfo.MoleDelta / amtEligibleAdj; foreach (var direction in Cardinal) { if ((eligibleAdjBits & direction) == 0 || !tile._adjacentTiles.TryGetValue(direction, out var tile2)) { continue; } tile.AdjustEqMovement(direction, molesToMove); tile._tileAtmosInfo.MoleDelta -= molesToMove; tile2._tileAtmosInfo.MoleDelta += molesToMove; } } giverTiles.Clear(); takerTiles.Clear(); foreach (var tile in tiles) { if (tile._tileAtmosInfo.MoleDelta > 0) { giverTiles.Add(tile); } else { takerTiles.Add(tile); } } // This is the part that can become O(n^2). if (giverTiles.Count < takerTiles.Count) { // as an optimization, we choose one of two methods based on which list is smaller. We really want to avoid O(n^2) if we can. var queue = new List <TileAtmosphere>(takerTiles.Count); foreach (var giver in giverTiles) { giver._tileAtmosInfo.CurrentTransferDirection = (Direction)(-1); giver._tileAtmosInfo.CurrentTransferAmount = 0; var queueCycleSlow = ++_gridAtmosphereComponent.EqualizationQueueCycleControl; queue.Clear(); queue.Add(giver); giver._tileAtmosInfo.LastSlowQueueCycle = queueCycleSlow; var queueCount = queue.Count; for (var i = 0; i < queueCount; i++) { if (giver._tileAtmosInfo.MoleDelta <= 0) { break; // We're done here now. Let's not do more work than needed. } var tile = queue[i]; foreach (var direction in Cardinal) { if (!tile._adjacentTiles.TryGetValue(direction, out var tile2)) { continue; } if (giver._tileAtmosInfo.MoleDelta <= 0) { break; // We're done here now. Let's not do more work than needed. } if (tile2?._tileAtmosInfo == null || tile2._tileAtmosInfo.LastQueueCycle != queueCycle) { continue; } if (tile2._tileAtmosInfo.LastSlowQueueCycle == queueCycleSlow) { continue; } queue.Add(tile2); queueCount++; tile2._tileAtmosInfo.LastSlowQueueCycle = queueCycleSlow; tile2._tileAtmosInfo.CurrentTransferDirection = direction.GetOpposite(); tile2._tileAtmosInfo.CurrentTransferAmount = 0; if (tile2._tileAtmosInfo.MoleDelta < 0) { // This tile needs gas. Let's give it to 'em. if (-tile2._tileAtmosInfo.MoleDelta > giver._tileAtmosInfo.MoleDelta) { // We don't have enough gas! tile2._tileAtmosInfo.CurrentTransferAmount -= giver._tileAtmosInfo.MoleDelta; tile2._tileAtmosInfo.MoleDelta += giver._tileAtmosInfo.MoleDelta; giver._tileAtmosInfo.MoleDelta = 0; } else { // We have enough gas. tile2._tileAtmosInfo.CurrentTransferAmount += tile2._tileAtmosInfo.MoleDelta; giver._tileAtmosInfo.MoleDelta += tile2._tileAtmosInfo.MoleDelta; tile2._tileAtmosInfo.MoleDelta = 0; } } } } // Putting this loop here helps make it O(n^2) over O(n^3) for (var i = queue.Count - 1; i >= 0; i--) { var tile = queue[i]; if (tile._tileAtmosInfo.CurrentTransferAmount != 0 && tile._tileAtmosInfo.CurrentTransferDirection != (Direction)(-1)) { tile.AdjustEqMovement(tile._tileAtmosInfo.CurrentTransferDirection, tile._tileAtmosInfo.CurrentTransferAmount); if (tile._adjacentTiles.TryGetValue(tile._tileAtmosInfo.CurrentTransferDirection, out var adjacent)) { adjacent._tileAtmosInfo.CurrentTransferAmount += tile._tileAtmosInfo.CurrentTransferAmount; } tile._tileAtmosInfo.CurrentTransferAmount = 0; } } } } else { var queue = new List <TileAtmosphere>(giverTiles.Count); foreach (var taker in takerTiles) { taker._tileAtmosInfo.CurrentTransferDirection = Direction.Invalid; taker._tileAtmosInfo.CurrentTransferAmount = 0; var queueCycleSlow = ++_gridAtmosphereComponent.EqualizationQueueCycleControl; queue.Clear(); queue.Add(taker); taker._tileAtmosInfo.LastSlowQueueCycle = queueCycleSlow; var queueCount = queue.Count; for (int i = 0; i < queueCount; i++) { if (taker._tileAtmosInfo.MoleDelta >= 0) { break; // We're done here now. Let's not do more work than needed. } var tile = queue[i]; foreach (var direction in Cardinal) { if (!tile._adjacentTiles.ContainsKey(direction)) { continue; } var tile2 = tile._adjacentTiles[direction]; if (taker._tileAtmosInfo.MoleDelta >= 0) { break; // We're done here now. Let's not do more work than needed. } if (tile2?._tileAtmosInfo == null || tile2._tileAtmosInfo.LastQueueCycle != queueCycle) { continue; } if (tile2._tileAtmosInfo.LastSlowQueueCycle == queueCycleSlow) { continue; } queue.Add(tile2); queueCount++; tile2._tileAtmosInfo.LastSlowQueueCycle = queueCycleSlow; tile2._tileAtmosInfo.CurrentTransferDirection = direction.GetOpposite(); tile2._tileAtmosInfo.CurrentTransferAmount = 0; if (tile2._tileAtmosInfo.MoleDelta > 0) { // This tile has gas we can suck, so let's if (tile2._tileAtmosInfo.MoleDelta > -taker._tileAtmosInfo.MoleDelta) { // They have enough gas tile2._tileAtmosInfo.CurrentTransferAmount -= taker._tileAtmosInfo.MoleDelta; tile2._tileAtmosInfo.MoleDelta += taker._tileAtmosInfo.MoleDelta; taker._tileAtmosInfo.MoleDelta = 0; } else { // They don't have enough gas! tile2._tileAtmosInfo.CurrentTransferAmount += tile2._tileAtmosInfo.MoleDelta; taker._tileAtmosInfo.MoleDelta += tile2._tileAtmosInfo.MoleDelta; tile2._tileAtmosInfo.MoleDelta = 0; } } } } for (var i = queue.Count - 1; i >= 0; i--) { var tile = queue[i]; if (tile._tileAtmosInfo.CurrentTransferAmount == 0 || tile._tileAtmosInfo.CurrentTransferDirection == Direction.Invalid) { continue; } tile.AdjustEqMovement(tile._tileAtmosInfo.CurrentTransferDirection, tile._tileAtmosInfo.CurrentTransferAmount); if (tile._adjacentTiles.TryGetValue(tile._tileAtmosInfo.CurrentTransferDirection, out var adjacent)) { adjacent._tileAtmosInfo.CurrentTransferAmount += tile._tileAtmosInfo.CurrentTransferAmount; } tile._tileAtmosInfo.CurrentTransferAmount = 0; } } } foreach (var tile in tiles) { tile.FinalizeEq(); } foreach (var tile in tiles) { foreach (var direction in Cardinal) { if (!tile._adjacentTiles.TryGetValue(direction, out var tile2)) { continue; } if (tile2?.Air?.Compare(Air) == GasMixture.GasCompareResult.NoExchange) { continue; } _gridAtmosphereComponent.AddActiveTile(tile2); break; } } } }
public static float Max(float a, float b, float c, float d) { return(MathF.Max(a, MathF.Max(b, MathF.Max(c, d)))); }
public static float Median(float a, float b, float c) { return(MathF.Max(MathF.Min(a, b), MathF.Min(MathF.Max(a, b), c))); }
public static float Clamp(this float val, float min, float max) { return(MathF.Clamp(val, min, max)); }