public void CheckForLavaAndWater(DwarfTime gameTime, ChunkManager chunks) { BoundingBox expandedBoundingBox = LocParent.BoundingBox.Expand(0.5f); List <Voxel> voxels = chunks.GetVoxelsIntersecting(expandedBoundingBox); foreach (Voxel currentVoxel in voxels) { WaterCell cell = currentVoxel.Water; if (cell.WaterLevel == 0) { continue; } else if (cell.Type == LiquidType.Lava) { Heat += 100; } else if (cell.Type == LiquidType.Water) { Heat -= 100; Heat = Math.Max(0.0f, Heat); } } }
public void FillDataFromChunk(VoxelChunk chunk) { for (int x = 0; x < Size.X; x++) { for (int y = 0; y < Size.Y; y++) { for (int z = 0; z < Size.Z; z++) { int index = chunk.Data.IndexAt(x, y, z); Voxel vox = chunk.MakeVoxel(x, y, z); WaterCell water = chunk.Data.Water[index]; if (vox == null) { Types[x, y, z] = 0; } else { Types[x, y, z] = vox.Type.ID; } if (water.WaterLevel > 0) { Liquid[x, y, z] = water.WaterLevel; LiquidTypes[x, y, z] = (short)water.Type; } else { Liquid[x, y, z] = 0; LiquidTypes[x, y, z] = 0; } } } } }
public void FillDataFromChunk(VoxelChunk chunk) { VoxelChunk.VoxelData data = chunk.Data; for (int x = 0; x < Size.X; x++) { for (int y = 0; y < Size.Y; y++) { for (int z = 0; z < Size.Z; z++) { int index = data.IndexAt(x, y, z); WaterCell water = data.Water[index]; Types[x, y, z] = data.Types[index]; Explored[x, y, z] = data.IsExplored[index]; if (water.WaterLevel > 0) { Liquid[x, y, z] = water.WaterLevel; LiquidTypes[x, y, z] = (byte)water.Type; } else { Liquid[x, y, z] = 0; LiquidTypes[x, y, z] = 0; } } } } }
public void HandleLiquidInteraction(VoxelHandle Vox, WaterCell From, WaterCell To) { if ((From.Type == LiquidType.Lava && To.Type == LiquidType.Water) || (From.Type == LiquidType.Water && To.Type == LiquidType.Lava)) { Vox.Type = VoxelLibrary.GetVoxelType("Stone"); Vox.WaterCell = WaterCell.Empty; } }
public void CreateTransfer(Vector3 worldPosition, WaterCell water1, WaterCell water2, byte amount) { Transfer transfer = new Transfer(); transfer.amount = amount; transfer.cellFrom = water1; transfer.cellTo = water2; transfer.worldLocation = worldPosition; Transfers.Enqueue(transfer); }
public void InitializeFromChunk(VoxelChunk chunk, GraphicsDevice graphics) { //chunk.PrimitiveMutex.WaitOne(); if (!chunk.IsVisible || IsBuilding) { // chunk.PrimitiveMutex.ReleaseMutex(); return; } IsBuilding = true; //chunk.PrimitiveMutex.ReleaseMutex(); accumulatedVertices.Clear(); faceExists.Clear(); drawFace.Clear(); int[,,] totalDepth = new int[chunk.SizeX, chunk.SizeY, chunk.SizeZ]; for (int x = 0; x < chunk.SizeX; x++) { for (int z = 0; z < chunk.SizeZ; z++) { bool drynessEncountered = false; int previousSum = 0; for (int y = 0; y < chunk.SizeY; y++) { WaterCell cell = chunk.Data.Water[chunk.Data.IndexAt(x, y, z)]; byte waterLevel = cell.WaterLevel; if (cell.Type != LiqType) { waterLevel = 0; } if (drynessEncountered) { if (waterLevel > 0) { drynessEncountered = false; previousSum += waterLevel; totalDepth[x, y, z] = previousSum; } } else { if (waterLevel > 0) { previousSum += waterLevel; totalDepth[x, y, z] = previousSum; } else { drynessEncountered = true; previousSum = 0; totalDepth[x, y, z] = 0; } } } } } int maxY = chunk.SizeY; if (chunk.Manager.ChunkData.Slice == ChunkManager.SliceMode.Y) { maxY = (int)Math.Min(chunk.Manager.ChunkData.MaxViewingLevel + 1, chunk.SizeY); } Voxel myVoxel = chunk.MakeVoxel(0, 0, 0); Voxel vox = chunk.MakeVoxel(0, 0, 0); for (int x = 0; x < chunk.SizeX; x++) { for (int y = 0; y < maxY; y++) { for (int z = 0; z < chunk.SizeZ; z++) { int index = chunk.Data.IndexAt(x, y, z); if (chunk.Data.Water[index].WaterLevel > 0 && chunk.Data.Water[index].Type == LiqType) { bool isTop = false; myVoxel.GridPosition = new Vector3(x, y, z); for (int i = 0; i < 6; i++) { BoxFace face = (BoxFace)i; if (face == BoxFace.Bottom) { continue; } Vector3 delta = faceDeltas[face]; bool success = chunk.Manager.ChunkData.GetVoxel(chunk, new Vector3(x + (int)delta.X, y + (int)delta.Y, z + (int)delta.Z) + chunk.Origin, ref vox); if (success) { if (face == BoxFace.Top) { if (vox.WaterLevel == 0 || y == (int)chunk.Manager.ChunkData.MaxViewingLevel) { drawFace[face] = true; } else { drawFace[face] = false; } } else { if (vox.WaterLevel == 0 && vox.IsEmpty) { drawFace[face] = true; } else { drawFace[face] = false; } bool gotVox = chunk.Manager.ChunkData.GetVoxel(chunk, new Vector3(x, y + 1, z) + chunk.Origin, ref vox); isTop = !gotVox || vox.IsEmpty || vox.WaterLevel == 0; } } else { drawFace[face] = true; } if (!drawFace[face]) { continue; } IEnumerable <ExtendedVertex> vertices = CreateWaterFace(myVoxel, face, chunk, x, y, z, totalDepth[x, y, z], isTop); foreach (ExtendedVertex newVertex in vertices.Select(vertex => new ExtendedVertex(vertex.Position + VertexNoise.GetRandomNoiseVector(vertex.Position), vertex.Color, vertex.VertColor, vertex.TextureCoordinate, vertex.TextureBounds))) { accumulatedVertices.Add(newVertex); } } } } } } try { ExtendedVertex[] vertex = new ExtendedVertex[accumulatedVertices.Count]; for (int i = 0; i < accumulatedVertices.Count; i++) { vertex[i] = accumulatedVertices[i]; } Vertices = vertex; chunk.PrimitiveMutex.WaitOne(); ResetBuffer(graphics); chunk.PrimitiveMutex.ReleaseMutex(); } catch (System.Threading.AbandonedMutexException e) { Console.Error.WriteLine(e.Message); } IsBuilding = false; }
public bool DiscreteUpdate(VoxelChunk chunk) { Vector3 gridCoord = new Vector3(0, 0, 0); bool updateOccurred = false; List<int> updateList = new List<int>(); WaterCell cellBelow = new WaterCell(); int maxSize = chunk.SizeX*chunk.SizeY*chunk.SizeZ; for (int i = 0; i < maxSize; i++) { WaterCell cell = chunk.Data.Water[i]; // Don't check empty cells or cells we've already modified. if (cell.WaterLevel < 1 || chunk.Data.Types[i] != 0) { continue; } updateList.Add(i); } if(updateList.Count == 0) { return false; } Voxel voxBelow = chunk.MakeVoxel(0, 0, 0); List<int> indices = Datastructures.RandomIndices(updateList.Count); // Loop through each cell. foreach(int t in indices) { int idx = updateList[indices[t]]; // Don't check empty cells or cells we've already modified. if (chunk.Data.Water[idx].WaterLevel < 1 || chunk.Data.Types[idx] != 0) { continue; } gridCoord = chunk.Data.CoordsAt(idx); int x = (int) gridCoord.X; int y = (int) gridCoord.Y; int z = (int) gridCoord.Z; Vector3 worldPos = gridCoord + chunk.Origin; if (chunk.Data.Water[idx].WaterLevel < EvaporationLevel && PlayState.Random.Next(0, 10) < 5) { if (chunk.Data.Water[idx].WaterLevel > 1) { chunk.Data.Water[idx].WaterLevel--; } else { chunk.Data.Water[idx].WaterLevel = 0; chunk.Data.Water[idx].Type = LiquidType.None; CreateSplash(worldPos, chunk.Data.Water[idx].Type); } updateOccurred = true; } bool shouldFall = false; // Now check the cell immediately below this one. // There are two cases, either we are at the bottom of the chunk, // in which case we must find the water from the chunk manager. // Otherwise, we just get the cell immediately beneath us. if(y > 0) { voxBelow.GridPosition = new Vector3(x, y - 1, z); if(voxBelow.IsEmpty) { cellBelow = voxBelow.Water; shouldFall = true; } } /* else { if(chunk.Manager.ChunkData.DoesWaterCellExist(worldPos)) { Voxel voxelsBelow = chunk.Manager.ChunkData.GetVoxel(chunk, worldPos + new Vector3(0, -1, 0)); if(voxelsBelow != null && voxelsBelow.IsEmpty) { cellBelow = chunk.Manager.ChunkData.GetWaterCellAtLocation(worldPos + new Vector3(0, -1, 0)); shouldFall = true; cellBelow.IsFalling = true; } } } */ // Cases where the fluid can fall down. if(shouldFall) { // If the cell immediately below us is empty, // swap the contents and move on. if(cellBelow.WaterLevel < 1) { cellBelow.WaterLevel = chunk.Data.Water[idx].WaterLevel; if(cellBelow.Type == LiquidType.None) { cellBelow.Type = chunk.Data.Water[idx].Type; } chunk.Data.Water[idx].WaterLevel = 0; chunk.Data.Water[idx].Type = LiquidType.None; chunk.Data.Water[idx].IsFalling = true; chunk.Data.Water[idx].HasChanged = true; cellBelow.HasChanged = true; voxBelow.Water = cellBelow; CreateSplash(worldPos, chunk.Data.Water[idx].Type); CreateTransfer(worldPos, chunk.Data.Water[idx], cellBelow, cellBelow.WaterLevel); updateOccurred = true; continue; } // Otherwise, fill as much of the space as we can. else { byte spaceLeft = (byte) (255 - cellBelow.WaterLevel); if(spaceLeft > 5) { CreateSplash(gridCoord + chunk.Origin, chunk.Data.Water[idx].Type); } // Special case where we can flow completely into the next cell. if (spaceLeft >= chunk.Data.Water[idx].WaterLevel) { byte transfer = chunk.Data.Water[idx].WaterLevel; cellBelow.WaterLevel += transfer; cellBelow.HasChanged = true; if(cellBelow.Type == LiquidType.None) { cellBelow.Type = chunk.Data.Water[idx].Type; } chunk.Data.Water[idx].WaterLevel = 0; chunk.Data.Water[idx].Type = LiquidType.None; chunk.Data.Water[idx].HasChanged = true; CreateTransfer(worldPos - Vector3.UnitY, chunk.Data.Water[idx], cellBelow, transfer); voxBelow.Water = cellBelow; updateOccurred = true; continue; } // Otherwise, only flow a little bit, and spread later. else { chunk.Data.Water[idx].WaterLevel -= spaceLeft; cellBelow.WaterLevel += spaceLeft; chunk.Data.Water[idx].HasChanged = true; cellBelow.HasChanged = true; if(cellBelow.Type == LiquidType.None) { cellBelow.Type = chunk.Data.Water[idx].Type; } CreateTransfer(worldPos - Vector3.UnitY, chunk.Data.Water[idx], cellBelow, spaceLeft); voxBelow.Water = cellBelow; } } } // Now the only fluid left can spread. // We spread to the manhattan neighbors //Array.Sort(m_spreadNeighbors, (a, b) => CompareFlowVectors(a, b, chunk.Data.Water[idx].FluidFlow)); Voxel neighbor = new Voxel(); foreach(Vector3 spread in m_spreadNeighbors) { bool success = chunk.Manager.ChunkData.GetVoxel(chunk, worldPos + spread, ref neighbor); if(!success) { continue; } if(!neighbor.IsEmpty) { continue; } WaterCell neighborWater = neighbor.Water; byte amountToMove = (byte)(Math.Min(255.0f - (float)neighborWater.WaterLevel, chunk.Data.Water[idx].WaterLevel) * GetSpreadRate(chunk.Data.Water[idx].Type)); if(amountToMove == 0) { continue; } if(neighborWater.WaterLevel < 2) { CreateSplash(worldPos + spread, chunk.Data.Water[idx].Type); updateOccurred = true; } CreateTransfer(worldPos + spread, chunk.Data.Water[idx], neighborWater, amountToMove); chunk.Data.Water[idx].WaterLevel -= amountToMove; neighborWater.WaterLevel += amountToMove; if(neighborWater.Type == LiquidType.None) { neighborWater.Type = chunk.Data.Water[idx].Type; } chunk.Data.Water[idx].HasChanged = true; neighborWater.HasChanged = true; neighbor.Water = neighborWater; if (chunk.Data.Water[idx].WaterLevel >= 1) { continue; } chunk.Data.Water[idx].WaterLevel = 0; chunk.Data.Water[idx].Type = LiquidType.None; break; } } return updateOccurred; }
new public void Update(DwarfTime gameTime, ChunkManager chunks, Camera camera) { Storm.InitializeStatics(chunks.World.ParticleManager); BoundingBox box = chunks.Bounds; box.Expand(10.0f); if (GlobalTransform.Translation.X < box.Min.X || GlobalTransform.Translation.X > box.Max.X || GlobalTransform.Translation.Z < box.Min.Z || GlobalTransform.Translation.Z > box.Max.Z) { Die(); } bool generateRainDrop = MathFunctions.RandEvent(Raininess); if (generateRainDrop) { for (int i = 0; i < MaxRainDrops; i++) { if (!RainDrops[i].IsAlive) { RainDrops[i].IsAlive = true; RainDrops[i].Pos = MathFunctions.RandVector3Box(BoundingBox); RainDrops[i].Pos = new Vector3(RainDrops[i].Pos.X, BoundingBox.Min.Y - 1, RainDrops[i].Pos.Z); RainDrops[i].Vel = Vector3.Down * Storm.Properties[TypeofStorm].RainSpeed + Velocity; break; } } } Voxel test = new Voxel(); Storm.StormProperties stormProperties = Storm.Properties[TypeofStorm]; for (int i = 0; i < MaxRainDrops; i++) { if (!RainDrops[i].IsAlive) { continue; } RainDrops[i].Pos += RainDrops[i].Vel * DwarfTime.Dt; if (stormProperties.RainRandom > 0) { RainDrops[i].Vel.X += MathFunctions.Rand(-1, 1) * stormProperties.RainRandom * DwarfTime.Dt; RainDrops[i].Vel.Z += MathFunctions.Rand(-1, 1) * stormProperties.RainRandom * DwarfTime.Dt; } if (RainDrops[i].Pos.Y < 0) { RainDrops[i].IsAlive = false; } if (!RainDrops[i].IsAlive && RainDrops[i].Particle != null) { RainDrops[i].Particle.LifeRemaining = -1; RainDrops[i].Particle = null; } else if (RainDrops[i].IsAlive && RainDrops[i].Particle == null) { RainDrops[i].Particle = stormProperties.RainEffect.Emitters[0].CreateParticle(RainDrops[i].Pos, RainDrops[i].Vel, Color.White); } else if (RainDrops[i].IsAlive && RainDrops[i].Particle != null) { RainDrops[i].Particle.Position = RainDrops[i].Pos; RainDrops[i].Particle.Velocity = RainDrops[i].Vel; } if (!chunks.ChunkData.GetVoxel(RainDrops[i].Pos, ref test)) { continue; } if (test == null || test.IsEmpty || test.WaterLevel > 0) { continue; } RainDrops[i].IsAlive = false; stormProperties.HitEffect.Trigger(1, RainDrops[i].Pos + Vector3.UnitY * 0.5f, Color.White); if (!MathFunctions.RandEvent(0.1f)) { continue; } Voxel above = test.IsEmpty ? test : test.GetVoxelAbove(); if (above == null) { continue; } if (stormProperties.CreatesLiquid && (above.WaterLevel < WaterManager.maxWaterLevel && (above.Water.Type == LiquidType.Water || above.Water.Type == LiquidType.None))) { WaterCell water = above.Water; water.WaterLevel = (byte)Math.Min(WaterManager.maxWaterLevel, water.WaterLevel + WaterManager.rainFallAmount); water.Type = stormProperties.LiquidToCreate; above.Water = water; above.Chunk.ShouldRebuildWater = true; } else if (stormProperties.CreatesVoxel && above.IsEmpty && above.WaterLevel == 0) { above.Type = stormProperties.VoxelToCreate; above.Water = new WaterCell(); above.Health = above.Type.StartingHealth; above.Chunk.NotifyTotalRebuild(!above.IsInterior); } } Matrix tf = LocalTransform; tf.Translation += Velocity * DwarfTime.Dt; LocalTransform = tf; base.Update(gameTime, chunks, camera); }
public static WaterCell[][][] WaterAllocate(int sx, int sy, int sz) { WaterCell[][][] w = new WaterCell[sx][][]; for(int x = 0; x < sx; x++) { w[x] = new WaterCell[sy][]; for(int y = 0; y < sy; y++) { w[x][y] = new WaterCell[sz]; for(int z = 0; z < sx; z++) { w[x][y][z] = new WaterCell(); } } } return w; }
public bool DiscreteUpdate(VoxelChunk chunk) { Vector3 gridCoord = new Vector3(0, 0, 0); bool updateOccurred = false; List <int> updateList = new List <int>(); WaterCell cellBelow = new WaterCell(); int maxSize = chunk.SizeX * chunk.SizeY * chunk.SizeZ; for (int i = 0; i < maxSize; i++) { WaterCell cell = chunk.Data.Water[i]; // Don't check empty cells or cells we've already modified. if (cell.WaterLevel < 1 || chunk.Data.Types[i] != 0) { continue; } updateList.Add(i); } if (updateList.Count == 0) { return(false); } Voxel voxBelow = chunk.MakeVoxel(0, 0, 0); List <int> indices = Datastructures.RandomIndices(updateList.Count); // Loop through each cell. foreach (int t in indices) { int idx = updateList[indices[t]]; // Don't check empty cells or cells we've already modified. if (chunk.Data.Water[idx].Type == LiquidType.None || chunk.Data.Types[idx] != 0) { continue; } gridCoord = chunk.Data.CoordsAt(idx); int x = (int)gridCoord.X; int y = (int)gridCoord.Y; int z = (int)gridCoord.Z; Vector3 worldPos = gridCoord + chunk.Origin; if (chunk.Data.Water[idx].WaterLevel <= EvaporationLevel && MathFunctions.RandEvent(0.01f)) { if (chunk.Data.Water[idx].WaterLevel > 1) { chunk.Data.Water[idx].WaterLevel--; } else { chunk.Data.Water[idx].WaterLevel = 0; if (chunk.Data.Water[idx].Type == LiquidType.Lava) { chunk.Data.Types[idx] = (byte)VoxelLibrary.GetVoxelType("Stone").ID; chunk.Data.Health[idx] = (byte)VoxelLibrary.GetVoxelType("Stone").StartingHealth; chunk.ShouldRebuild = true; chunk.ShouldRecalculateLighting = true; } chunk.Data.Water[idx].Type = LiquidType.None; } updateOccurred = true; } bool shouldFall = false; // Now check the cell immediately below this one. // There are two cases, either we are at the bottom of the chunk, // in which case we must find the water from the chunk manager. // Otherwise, we just get the cell immediately beneath us. if (y > 0) { voxBelow.GridPosition = new Vector3(x, y - 1, z); if (voxBelow.IsEmpty) { cellBelow = voxBelow.Water; shouldFall = true; } } /* * else * { * if(chunk.Manager.ChunkData.DoesWaterCellExist(worldPos)) * { * Voxel voxelsBelow = chunk.Manager.ChunkData.GetVoxel(chunk, worldPos + new Vector3(0, -1, 0)); * * if(voxelsBelow != null && voxelsBelow.IsEmpty) * { * cellBelow = chunk.Manager.ChunkData.GetWaterCellAtLocation(worldPos + new Vector3(0, -1, 0)); * shouldFall = true; * cellBelow.IsFalling = true; * } * } * } */ // Cases where the fluid can fall down. if (shouldFall) { // If the cell immediately below us is empty, // swap the contents and move on. if (cellBelow.WaterLevel < 1) { CreateSplash(worldPos, chunk.Data.Water[idx].Type); cellBelow.WaterLevel = chunk.Data.Water[idx].WaterLevel; if (cellBelow.Type == LiquidType.None) { cellBelow.Type = chunk.Data.Water[idx].Type; } chunk.Data.Water[idx].WaterLevel = 0; chunk.Data.Water[idx].Type = LiquidType.None; voxBelow.Water = cellBelow; CreateTransfer(worldPos, chunk.Data.Water[idx], cellBelow, cellBelow.WaterLevel); updateOccurred = true; continue; } // Otherwise, fill as much of the space as we can. else { byte spaceLeft = (byte)(8 - cellBelow.WaterLevel); // Special case where we can flow completely into the next cell. if (spaceLeft >= chunk.Data.Water[idx].WaterLevel) { byte transfer = chunk.Data.Water[idx].WaterLevel; cellBelow.WaterLevel += transfer; if (cellBelow.Type == LiquidType.None) { cellBelow.Type = chunk.Data.Water[idx].Type; } chunk.Data.Water[idx].WaterLevel = 0; chunk.Data.Water[idx].Type = LiquidType.None; CreateTransfer(worldPos - Vector3.UnitY, chunk.Data.Water[idx], cellBelow, transfer); voxBelow.Water = cellBelow; updateOccurred = true; continue; } // Otherwise, only flow a little bit, and spread later. else { chunk.Data.Water[idx].WaterLevel -= spaceLeft; cellBelow.WaterLevel += spaceLeft; if (cellBelow.Type == LiquidType.None) { cellBelow.Type = chunk.Data.Water[idx].Type; } CreateTransfer(worldPos - Vector3.UnitY, chunk.Data.Water[idx], cellBelow, spaceLeft); voxBelow.Water = cellBelow; } } } // Now the only fluid left can spread. // We spread to the manhattan neighbors //Array.Sort(m_spreadNeighbors, (a, b) => CompareFlowVectors(a, b, chunk.Data.Water[idx].FluidFlow)); m_spreadNeighbors.Shuffle(); Voxel neighbor = new Voxel(); foreach (Vector3 spread in m_spreadNeighbors) { bool success = chunk.Manager.ChunkData.GetVoxel(chunk, worldPos + spread, ref neighbor); if (!success) { continue; } if (!neighbor.IsEmpty) { continue; } WaterCell neighborWater = neighbor.Water; if (neighborWater.WaterLevel >= chunk.Data.Water[idx].WaterLevel) { continue; } byte amountToMove = (byte)(Math.Min(8.0f - (float)neighborWater.WaterLevel, chunk.Data.Water[idx].WaterLevel) * GetSpreadRate(chunk.Data.Water[idx].Type)); if (amountToMove == 0) { continue; } if (neighborWater.WaterLevel < 2) { updateOccurred = true; } CreateTransfer(worldPos + spread, chunk.Data.Water[idx], neighborWater, amountToMove); chunk.Data.Water[idx].WaterLevel -= amountToMove; neighborWater.WaterLevel += amountToMove; if (neighborWater.Type == LiquidType.None) { neighborWater.Type = chunk.Data.Water[idx].Type; } neighbor.Water = neighborWater; if (chunk.Data.Water[idx].WaterLevel >= 1) { continue; } chunk.Data.Water[idx].WaterLevel = 0; chunk.Data.Water[idx].Type = LiquidType.None; break; } } return(updateOccurred); }
public override void Update(DwarfTime gameTime, ChunkManager chunks, Camera camera) { Storm.InitializeStatics(); BoundingBox box = chunks.Bounds; box.Expand(10.0f); if (GlobalTransform.Translation.X < box.Min.X || GlobalTransform.Translation.X > box.Max.X || GlobalTransform.Translation.Z < box.Min.Z || GlobalTransform.Translation.Z > box.Max.Z) { Die(); } bool generateRainDrop = MathFunctions.RandEvent(Raininess); if (generateRainDrop) { for (int i = 0; i < MaxRainDrops; i++) { if (!RainDrops[i].IsAlive) { RainDrops[i].IsAlive = true; RainDrops[i].Pos = MathFunctions.RandVector3Box(BoundingBox); RainDrops[i].Pos = new Vector3(RainDrops[i].Pos.X, BoundingBox.Min.Y - 1, RainDrops[i].Pos.Z); RainDrops[i].Vel = Vector3.Down * Storm.Properties[TypeofStorm].RainSpeed + Velocity; break; } } } Storm.StormProperties stormProperties = Storm.Properties[TypeofStorm]; var rainEmitter = World.ParticleManager.Effects[stormProperties.RainEffect]; var hitEmitter = World.ParticleManager.Effects[stormProperties.HitEffect]; for (int i = 0; i < MaxRainDrops; i++) { if (!RainDrops[i].IsAlive) { continue; } RainDrops[i].Pos += RainDrops[i].Vel * DwarfTime.Dt; if (stormProperties.RainRandom > 0) { RainDrops[i].Vel.X += MathFunctions.Rand(-1, 1) * stormProperties.RainRandom * DwarfTime.Dt; RainDrops[i].Vel.Z += MathFunctions.Rand(-1, 1) * stormProperties.RainRandom * DwarfTime.Dt; } if (RainDrops[i].Pos.Y < 0) { RainDrops[i].IsAlive = false; } if (!RainDrops[i].IsAlive && RainDrops[i].Particle != null) { RainDrops[i].Particle.LifeRemaining = -1; RainDrops[i].Particle = null; } else if (RainDrops[i].IsAlive && RainDrops[i].Particle == null) { RainDrops[i].Particle = rainEmitter.Emitters[0].CreateParticle(RainDrops[i].Pos, RainDrops[i].Vel, Color.White); } else if (RainDrops[i].IsAlive && RainDrops[i].Particle != null) { RainDrops[i].Particle.Position = RainDrops[i].Pos; RainDrops[i].Particle.Velocity = RainDrops[i].Vel; } var test = new VoxelHandle(chunks.ChunkData, GlobalVoxelCoordinate.FromVector3(RainDrops[i].Pos)); if (!test.IsValid || test.IsEmpty || test.WaterCell.WaterLevel > 0) { continue; } RainDrops[i].IsAlive = false; hitEmitter.Trigger(1, RainDrops[i].Pos + Vector3.UnitY * 0.5f, Color.White); //if (!MathFunctions.RandEvent(0.1f)) continue; var above = test.IsEmpty ? test : VoxelHelpers.GetVoxelAbove(test); if (!above.IsValid || !above.IsEmpty) { continue; } if (TypeofStorm == StormType.RainStorm && (above.WaterCell.WaterLevel < WaterManager.maxWaterLevel && (above.WaterCell.Type == LiquidType.Water))) { WaterCell water = above.WaterCell; water.WaterLevel = (byte)Math.Min(WaterManager.maxWaterLevel, water.WaterLevel + WaterManager.rainFallAmount); water.Type = stormProperties.LiquidToCreate; above.WaterCell = water; } else if (TypeofStorm == StormType.SnowStorm && above.IsEmpty && above.WaterCell.WaterLevel == 0) { if (test.GrassType == 0) { test.GrassType = GrassLibrary.GetGrassType("snow").ID; } else { var existingGrass = GrassLibrary.GetGrassType((byte)test.GrassType); if (!String.IsNullOrEmpty(existingGrass.BecomeWhenSnowedOn)) { test.GrassType = GrassLibrary.GetGrassType(existingGrass.BecomeWhenSnowedOn).ID; } } } } Matrix tf = LocalTransform; tf.Translation += Velocity * DwarfTime.Dt; LocalTransform = tf; base.Update(gameTime, chunks, camera); }