Пример #1
0
        private void MergeAtmospheres(MapIndices pos)
        {
            var adjacent = new HashSet <Atmosphere>(GetAdjacentAtmospheres(pos).Values);

            // If this block doesn't separate two atmospheres, there's nothing to do
            if (adjacent.Count <= 1)
            {
                return;
            }

            var allCells = new List <MapIndices> {
                pos
            };

            foreach (var atmos in adjacent)
            {
                allCells.AddRange(FindRoomContents(atmos));
            }

            // Fuse all adjacent atmospheres
            Atmosphere replacement;

            if (adjacent.Contains(null))
            {
                replacement = null;
            }
            else
            {
                replacement = new Atmosphere(GetVolumeForCells(allCells.Count));
                foreach (var atmos in adjacent)
                {
                    if (atmos == null)
                    {
                        continue;
                    }

                    // Copy all the gasses across
                    foreach (var gas in atmos.Gasses)
                    {
                        replacement.Add(gas.Gas, gas.Volume, atmos.Temperature);
                    }
                }
            }

            foreach (var cellPos in allCells)
            {
                _atmospheres[cellPos] = replacement;
            }
        }
Пример #2
0
        private IEnumerable <MapIndices> FindRoomContents(Atmosphere atmos)
        {
            // TODO this is O(n) with respect to the map size, so solve this some other way
            var poses = new List <MapIndices>();

            foreach (var(pos, cellAtmos) in _atmospheres)
            {
                if (cellAtmos == atmos)
                {
                    poses.Add(pos);
                }
            }

            return(poses);
        }
Пример #3
0
        private Atmosphere GetAtmosphere(MapIndices pos)
        {
            if (_atmospheres.TryGetValue(pos, out var atmosphere))
            {
                return(atmosphere);
            }

            // If this is clearly space - such as someone moving round outside the station - just return immediately
            // and don't add anything to the grid map
            if (IsSpace(pos))
            {
                return(null);
            }

            // If the block is obstructed:
            // If the air blocker is marked as 'use adjacent atmosphere' then the cell behaves as if
            // you got one of it's adjacent atmospheres. If not, it returns null.
            var obstruction = GetObstructingComponent(pos);

            if (obstruction != null)
            {
                return(obstruction.UseAdjacentAtmosphere ? GetAdjacentAtmospheres(pos).FirstOrDefault().Value : null);
            }

            var connected = FindConnectedCells(pos);

            if (connected == null)
            {
                // Since this is on a floor tile, it's fairly likely this is a room with
                // a breach. As such, cache this position for sake of static objects like
                // air vents which call this constantly.
                _atmospheres[pos] = null;
                return(null);
            }

            // TODO create default atmosphere
            atmosphere = new Atmosphere(GetVolumeForCells(connected.Count));

            foreach (var c in connected)
            {
                _atmospheres[c] = atmosphere;
            }

            return(atmosphere);
        }
Пример #4
0
        private void SplitAtmospheres(MapIndices pos)
        {
            // Remove the now-covered atmosphere
            _atmospheres.Remove(pos);

            var adjacent            = GetAdjacentAtmospheres(pos);
            var adjacentPositions   = adjacent.Select(p => pos.Offset(p.Key)).ToList();
            var adjacentAtmospheres = new HashSet <Atmosphere>(adjacent.Values);

            foreach (var atmos in adjacentAtmospheres)
            {
                var i        = 0;
                int?spaceIdx = null;
                var sides    = new Dictionary <MapIndices, int>();

                foreach (var pair in adjacent.Where(p => p.Value == atmos))
                {
                    var edgePos = pos.Offset(pair.Key);
                    if (sides.ContainsKey(edgePos))
                    {
                        continue;
                    }

                    var connected = FindConnectedCells(edgePos);
                    if (connected == null)
                    {
                        if (spaceIdx == null)
                        {
                            spaceIdx = i++;
                        }
                        sides[edgePos] = (int)spaceIdx;
                        continue;
                    }

                    foreach (var connectedPos in connected.Intersect(adjacentPositions))
                    {
                        sides[connectedPos] = i;
                    }

                    i++;
                }

                // If the sides were all connected, this atmosphere is intact
                // TODO in some way adjust the atmosphere volume
                if (i == 1)
                {
                    continue;
                }

                // If any of the sides that used to have this atmosphere are now exposed to space, remove
                // all the old atmosphere's cells.
                if (spaceIdx != null)
                {
                    foreach (var rpos in FindRoomContents(atmos))
                    {
                        _atmospheres.Remove(rpos);
                    }
                }

                // Split up each of the sides
                for (var j = 0; j < i; j++)
                {
                    // Find a position to represent this
                    var basePos = sides.First(p => p.Value == j).Key;

                    var connected = FindConnectedCells(basePos);

                    if (connected == null)
                    {
                        continue;
                    }

                    var newAtmos = new Atmosphere(GetVolumeForCells(connected.Count));

                    // Copy over contents of atmos, scaling it down to maintain the partial pressure
                    if (atmos != null)
                    {
                        newAtmos.Temperature = atmos.Temperature;
                        foreach (var gas in atmos.Gasses)
                        {
                            newAtmos.SetQuantity(gas.Gas, gas.Volume * newAtmos.Volume / atmos.Volume);
                        }
                    }

                    foreach (var cpos in connected)
                    {
                        _atmospheres[cpos] = newAtmos;
                    }
                }
            }
        }