示例#1
0
        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);
                }
            }
        }
示例#2
0
        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;
                        }
                    }
                }
            }
        }
示例#3
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;
                        }
                    }
                }
            }
        }
示例#4
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;
     }
 }
示例#5
0
        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);
        }
示例#6
0
        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;
        }
示例#7
0
        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;
        }
示例#8
0
        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);
        }
示例#9
0
            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);
            }
示例#10
0
        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;
        }
示例#11
0
        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);
        }
示例#12
0
        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);
        }