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